Source Code Cross Referenced for AbstractComponent.java in  » Ajax » zk » org » zkoss » zk » ui » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Ajax » zk » org.zkoss.zk.ui 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* AbstractComponent.java
0002:
0003:        {{IS_NOTE
0004:        	Purpose:
0005:        		
0006:        	Description:
0007:        		
0008:        	History:
0009:        		Mon May 30 21:49:42     2005, Created by tomyeh
0010:        }}IS_NOTE
0011:
0012:        Copyright (C) 2005 Potix Corporation. All Rights Reserved.
0013:
0014:        {{IS_RIGHT
0015:        	This program is distributed under GPL Version 2.0 in the hope that
0016:        	it will be useful, but WITHOUT ANY WARRANTY.
0017:        }}IS_RIGHT
0018:         */
0019:        package org.zkoss.zk.ui;
0020:
0021:        import java.util.Iterator;
0022:        import java.util.ListIterator;
0023:        import java.util.Set;
0024:        import java.util.HashSet;
0025:        import java.util.List;
0026:        import java.util.AbstractSequentialList;
0027:        import java.util.LinkedList;
0028:        import java.util.Collection;
0029:        import java.util.Collections;
0030:        import java.util.Map;
0031:        import java.util.HashMap;
0032:        import java.io.Writer;
0033:        import java.io.IOException;
0034:
0035:        import org.zkoss.lang.D;
0036:        import org.zkoss.lang.Classes;
0037:        import org.zkoss.lang.Objects;
0038:        import org.zkoss.util.CollectionsX;
0039:        import org.zkoss.util.logging.Log;
0040:        import org.zkoss.io.Serializables;
0041:        import org.zkoss.xml.HTMLs;
0042:
0043:        import org.zkoss.zk.mesg.MZk;
0044:        import org.zkoss.zk.ui.event.EventListener;
0045:        import org.zkoss.zk.ui.event.Deferrable;
0046:        import org.zkoss.zk.ui.event.Event;
0047:        import org.zkoss.zk.ui.event.ForwardEvent;
0048:        import org.zkoss.zk.ui.event.Events;
0049:        import org.zkoss.zk.ui.ext.Macro;
0050:        import org.zkoss.zk.ui.ext.RawId;
0051:        import org.zkoss.zk.ui.ext.NonFellow;
0052:        import org.zkoss.zk.ui.ext.render.ZidRequired;
0053:        import org.zkoss.zk.ui.render.ComponentRenderer;
0054:        import org.zkoss.zk.ui.util.ComponentSerializationListener;
0055:        import org.zkoss.zk.ui.util.ComponentCloneListener;
0056:        import org.zkoss.zk.ui.util.DeferredValue;
0057:        import org.zkoss.zk.ui.sys.ExecutionCtrl;
0058:        import org.zkoss.zk.ui.sys.ExecutionsCtrl;
0059:        import org.zkoss.zk.ui.sys.ComponentCtrl;
0060:        import org.zkoss.zk.ui.sys.ComponentsCtrl;
0061:        import org.zkoss.zk.ui.sys.PageCtrl;
0062:        import org.zkoss.zk.ui.sys.DesktopCtrl;
0063:        import org.zkoss.zk.ui.sys.SessionCtrl;
0064:        import org.zkoss.zk.ui.sys.WebAppCtrl;
0065:        import org.zkoss.zk.ui.sys.UiEngine;
0066:        import org.zkoss.zk.ui.sys.IdGenerator;
0067:        import org.zkoss.zk.ui.sys.Names;
0068:        import org.zkoss.zk.ui.metainfo.AnnotationMap;
0069:        import org.zkoss.zk.ui.metainfo.Annotation;
0070:        import org.zkoss.zk.ui.metainfo.EventHandlerMap;
0071:        import org.zkoss.zk.ui.metainfo.ComponentDefinition;
0072:        import org.zkoss.zk.ui.metainfo.PageDefinition;
0073:        import org.zkoss.zk.ui.metainfo.LanguageDefinition;
0074:        import org.zkoss.zk.ui.metainfo.ComponentInfo;
0075:        import org.zkoss.zk.ui.metainfo.ComponentDefinition;
0076:        import org.zkoss.zk.ui.metainfo.ComponentDefinitionMap;
0077:        import org.zkoss.zk.ui.metainfo.DefinitionNotFoundException;
0078:        import org.zkoss.zk.ui.metainfo.EventHandler;
0079:        import org.zkoss.zk.ui.metainfo.ZScript;
0080:        import org.zkoss.zk.ui.impl.ListenerIterator;
0081:        import org.zkoss.zk.fn.ZkFns;
0082:        import org.zkoss.zk.au.AuResponse;
0083:        import org.zkoss.zk.au.out.AuClientInfo;
0084:        import org.zkoss.zk.scripting.Namespace;
0085:        import org.zkoss.zk.scripting.Interpreter;
0086:        import org.zkoss.zk.scripting.util.SimpleNamespace;
0087:
0088:        /**
0089:         * A skeletal implementation of {@link Component}. Though it is OK
0090:         * to implement Component from scratch, this class simplifies some of
0091:         * the chores.
0092:         *
0093:         * @author tomyeh
0094:         */
0095:        public class AbstractComponent implements  Component, ComponentCtrl,
0096:                java.io.Serializable {
0097:            //	private static final Log log = Log.lookup(AbstractComponent.class);
0098:            private static final long serialVersionUID = 20070920L;
0099:
0100:            private transient Page _page;
0101:            private String _id;
0102:            private String _uuid;
0103:            private transient ComponentDefinition _def;
0104:            /** The mold (default: "default"). */
0105:            private String _mold = "default";
0106:            /** The info of the ID space, or null if IdSpace is NOT implemented. */
0107:            private transient SpaceInfo _spaceInfo;
0108:            private transient Map _attrs;
0109:            //don't create it dynamically because _ip bind it at constructor
0110:            /** A map of event listener: Map(evtnm, EventListener)). */
0111:            private transient Map _listeners;
0112:            /** The extra controls. */
0113:            private transient Object _xtrl;
0114:
0115:            /** The list used for {@link #getChildren} only. */
0116:            private transient List _apiChildren;
0117:            private transient AbstractComponent _parent;
0118:            /** The next sibling. */
0119:            private transient AbstractComponent _next;
0120:            /** The previous sibling. */
0121:            private transient AbstractComponent _prev;
0122:            /** The first child. */
0123:            private transient AbstractComponent _first;
0124:            /** The last child. */
0125:            private transient AbstractComponent _last;
0126:            /** # of children. */
0127:            private int _nChild;
0128:            /** The modification count used to avoid co-modification of _next, _prev..
0129:             */
0130:            private transient int _modCntChd;
0131:            /** A set of components that are being removed.
0132:             * It is used to prevent dead-loop between {@link #removeChild}
0133:             * and {@link #setParent}.
0134:             */
0135:            private transient Set _rming;
0136:            /** A set of components that are being added.
0137:             * It is used to prevent dead-loop between {@link #insertBefore}
0138:             * and {@link #setParent}.
0139:             */
0140:            private transient Set _adding;
0141:
0142:            /** A map of annotations. Serializable since a component might have
0143:             * its own annotations.
0144:             */
0145:            private AnnotationMap _annots;
0146:            /** A map of event handler to handle events. */
0147:            private EventHandlerMap _evthds;
0148:            /** A map of forward conditions:
0149:             * Map(String orgEvt, [listener, List([target or targetPath,targetEvent])]).
0150:             */
0151:            private transient Map _forwards;
0152:            /** Whether _annots is shared with other components. */
0153:            private transient boolean _annotsShared;
0154:            /** Whether _evthds is shared with other components. */
0155:            private transient boolean _evthdsShared;
0156:            /** Whether this component is visible. */
0157:            private boolean _visible = true;
0158:
0159:            /** Constructs a component with auto-generated ID.
0160:             */
0161:            protected AbstractComponent() {
0162:                final Execution exec = Executions.getCurrent();
0163:
0164:                final Object curInfo = ComponentsCtrl.getCurrentInfo();
0165:                if (curInfo != null) {
0166:                    ComponentsCtrl.setCurrentInfo((ComponentInfo) null); //to avoid mis-use
0167:                    if (curInfo instanceof  ComponentInfo) {
0168:                        final ComponentInfo compInfo = (ComponentInfo) curInfo;
0169:                        _def = compInfo.getComponentDefinition();
0170:                        addSharedAnnotationMap(_def.getAnnotationMap());
0171:                        addSharedAnnotationMap(compInfo.getAnnotationMap());
0172:                    } else {
0173:                        _def = (ComponentDefinition) curInfo;
0174:                        addSharedAnnotationMap(_def.getAnnotationMap());
0175:                    }
0176:                } else {
0177:                    _def = lookupDefinition(exec, getClass());
0178:                    if (_def != null)
0179:                        addSharedAnnotationMap(_def.getAnnotationMap());
0180:                    else if ((this  instanceof  Macro)
0181:                            && System
0182:                                    .getProperty("org.zkoss.zk.MacroNoDefinitionAllowed") == null)
0183:                        //3.0.3: check addition prop to allow user to maintain backward compatibility
0184:                        throw new DefinitionNotFoundException(
0185:                                "Component definition not found for the macro "
0186:                                        + this .getClass()
0187:                                        + ". Current page definition: "
0188:                                        + (exec != null ? ""
0189:                                                + ((ExecutionCtrl) exec)
0190:                                                        .getCurrentPageDefinition()
0191:                                                : "n/a")
0192:                                        + ". Current page: "
0193:                                        + (exec != null ? ""
0194:                                                + ((ExecutionCtrl) exec)
0195:                                                        .getCurrentPage()
0196:                                                : "n/a"));
0197:                    else
0198:                        _def = ComponentsCtrl.DUMMY;
0199:                }
0200:
0201:                init(false);
0202:
0203:                _spaceInfo = this  instanceof  IdSpace ? new SpaceInfo(this )
0204:                        : null;
0205:
0206:                //		if (D.ON && log.debugable()) log.debug("Create comp: "+this);
0207:            }
0208:
0209:            private static final ComponentDefinition lookupDefinition(
0210:                    Execution exec, Class cls) {
0211:                if (exec != null) {
0212:                    final ExecutionCtrl execCtrl = (ExecutionCtrl) exec;
0213:                    final PageDefinition pgdef = execCtrl
0214:                            .getCurrentPageDefinition();
0215:                    final Page page = execCtrl.getCurrentPage();
0216:
0217:                    final ComponentDefinition compdef = pgdef != null ? pgdef
0218:                            .getComponentDefinition(cls, true)
0219:                            : page != null ? page.getComponentDefinition(cls,
0220:                                    true) : null;
0221:                    if (compdef != null)
0222:                        return compdef;
0223:
0224:                    return lookupDefinitionByDeviceType(exec.getDesktop()
0225:                            .getDeviceType(), cls);
0226:                }
0227:
0228:                for (Iterator it = LanguageDefinition.getDeviceTypes()
0229:                        .iterator(); it.hasNext();) {
0230:                    final ComponentDefinition compdef = lookupDefinitionByDeviceType(
0231:                            (String) it.next(), cls);
0232:                    if (compdef != null)
0233:                        return compdef;
0234:                }
0235:                return null;
0236:            }
0237:
0238:            private static final ComponentDefinition lookupDefinitionByDeviceType(
0239:                    String deviceType, Class cls) {
0240:                for (Iterator it = LanguageDefinition.getByDeviceType(
0241:                        deviceType).iterator(); it.hasNext();) {
0242:                    final LanguageDefinition ld = (LanguageDefinition) it
0243:                            .next();
0244:                    try {
0245:                        return ld.getComponentDefinition(cls);
0246:                    } catch (DefinitionNotFoundException ex) { //ignore
0247:                    }
0248:                }
0249:                return null;
0250:            }
0251:
0252:            /** Initialize for contructor and serialization.
0253:             * @param cloning whether this method is called by clone()
0254:             */
0255:            private void init(boolean cloning) {
0256:                _apiChildren = new AbstractSequentialList() {
0257:                    public int size() {
0258:                        return _nChild;
0259:                    }
0260:
0261:                    public ListIterator listIterator(int index) {
0262:                        return new ChildIter(index);
0263:                    }
0264:                };
0265:
0266:                if (!cloning)
0267:                    _attrs = new HashMap(4);
0268:            }
0269:
0270:            /** Adds to the ID spaces, if any, when ID is changed.
0271:             * Caller has to make sure the uniqueness.
0272:             */
0273:            private static void addToIdSpaces(final Component comp) {
0274:                if (comp instanceof  IdSpace)
0275:                    ((AbstractComponent) comp).bindToIdSpace(comp);
0276:
0277:                final IdSpace is = getSpaceOwnerOfParent(comp);
0278:                if (is instanceof  Component)
0279:                    ((AbstractComponent) is).bindToIdSpace(comp);
0280:                else if (is != null)
0281:                    ((PageCtrl) is).addFellow(comp);
0282:            }
0283:
0284:            private static final IdSpace getSpaceOwnerOfParent(Component comp) {
0285:                final Component parent = comp.getParent();
0286:                if (parent != null)
0287:                    return parent.getSpaceOwner();
0288:                else
0289:                    return comp.getPage();
0290:            }
0291:
0292:            /** Removes from the ID spaces, if any, when ID is changed. */
0293:            private static void removeFromIdSpaces(final Component comp) {
0294:                final AbstractComponent abcomp = (AbstractComponent) comp;
0295:                final String compId = abcomp._id;
0296:                if (compId == null || (comp instanceof  NonFellow)
0297:                        || ComponentsCtrl.isAutoId(compId))
0298:                    return; //nothing to do
0299:
0300:                if (comp instanceof  IdSpace)
0301:                    abcomp.unbindFromIdSpace(compId);
0302:
0303:                final IdSpace is = getSpaceOwnerOfParent(comp);
0304:                if (is instanceof  Component)
0305:                    ((AbstractComponent) is).unbindFromIdSpace(compId);
0306:                else if (is != null)
0307:                    ((PageCtrl) is).removeFellow(comp);
0308:            }
0309:
0310:            /** Checks the uniqueness in ID space when changing ID. */
0311:            private static void checkIdSpaces(final AbstractComponent comp,
0312:                    String newId) {
0313:                if (comp instanceof  NonFellow)
0314:                    return; //no need to check
0315:
0316:                if (comp instanceof  IdSpace
0317:                        && comp._spaceInfo.fellows.containsKey(newId))
0318:                    throw new UiException("Not unique in the ID space of "
0319:                            + comp);
0320:
0321:                final IdSpace is = getSpaceOwnerOfParent(comp);
0322:                if (is instanceof  Component) {
0323:                    if (((AbstractComponent) is)._spaceInfo.fellows
0324:                            .containsKey(newId))
0325:                        throw new UiException("Not unique in the ID space of "
0326:                                + is);
0327:                } else if (is != null) {
0328:                    if (((PageCtrl) is).hasFellow(newId))
0329:                        throw new UiException("Not unique in the ID space of "
0330:                                + is);
0331:                }
0332:            }
0333:
0334:            /** Adds its descendants to the ID space when parent or page is changed,
0335:             * excluding comp.
0336:             */
0337:            private static void addToIdSpacesDown(Component comp) {
0338:                final IdSpace is = getSpaceOwnerOfParent(comp);
0339:                if (is instanceof  Component)
0340:                    addToIdSpacesDown(comp, (Component) is);
0341:                else if (is != null)
0342:                    addToIdSpacesDown(comp, (PageCtrl) is);
0343:            }
0344:
0345:            private static void addToIdSpacesDown(Component comp,
0346:                    Component owner) {
0347:                if (!(comp instanceof  NonFellow)
0348:                        && !ComponentsCtrl.isAutoId(comp.getId()))
0349:                    ((AbstractComponent) owner).bindToIdSpace(comp);
0350:                if (!(comp instanceof  IdSpace))
0351:                    for (Iterator it = comp.getChildren().iterator(); it
0352:                            .hasNext();)
0353:                        addToIdSpacesDown((Component) it.next(), owner); //recursive
0354:            }
0355:
0356:            private static void addToIdSpacesDown(Component comp, PageCtrl owner) {
0357:                if (!(comp instanceof  NonFellow)
0358:                        && !ComponentsCtrl.isAutoId(comp.getId()))
0359:                    owner.addFellow(comp);
0360:                if (!(comp instanceof  IdSpace))
0361:                    for (Iterator it = comp.getChildren().iterator(); it
0362:                            .hasNext();)
0363:                        addToIdSpacesDown((Component) it.next(), owner); //recursive
0364:            }
0365:
0366:            /** Adds its descendants to the ID space when parent or page is changed,
0367:             * excluding comp.
0368:             */
0369:            private static void removeFromIdSpacesDown(Component comp) {
0370:                final IdSpace is = getSpaceOwnerOfParent(comp);
0371:                if (is instanceof  Component)
0372:                    removeFromIdSpacesDown(comp, (Component) is);
0373:                else if (is != null)
0374:                    removeFromIdSpacesDown(comp, (PageCtrl) is);
0375:            }
0376:
0377:            private static void removeFromIdSpacesDown(Component comp,
0378:                    Component owner) {
0379:                final String compId = comp.getId();
0380:                if (!(comp instanceof  NonFellow)
0381:                        && !ComponentsCtrl.isAutoId(compId))
0382:                    ((AbstractComponent) owner).unbindFromIdSpace(compId);
0383:                if (!(comp instanceof  IdSpace))
0384:                    for (Iterator it = comp.getChildren().iterator(); it
0385:                            .hasNext();)
0386:                        removeFromIdSpacesDown((Component) it.next(), owner); //recursive
0387:            }
0388:
0389:            private static void removeFromIdSpacesDown(Component comp,
0390:                    PageCtrl owner) {
0391:                if (!(comp instanceof  NonFellow)
0392:                        && !ComponentsCtrl.isAutoId(comp.getId()))
0393:                    owner.removeFellow(comp);
0394:                if (!(comp instanceof  IdSpace))
0395:                    for (Iterator it = comp.getChildren().iterator(); it
0396:                            .hasNext();)
0397:                        removeFromIdSpacesDown((Component) it.next(), owner); //recursive
0398:            }
0399:
0400:            /** Checks the uniqueness in ID space when changing parent. */
0401:            private static void checkIdSpacesDown(Component comp,
0402:                    Component newparent) {
0403:                final IdSpace is = newparent.getSpaceOwner();
0404:                if (is instanceof  Component)
0405:                    checkIdSpacesDown(comp, ((AbstractComponent) is)._spaceInfo);
0406:                else if (is != null)
0407:                    checkIdSpacesDown(comp, (PageCtrl) is);
0408:            }
0409:
0410:            /** Checks comp and its descendants for the specified SpaceInfo. */
0411:            private static void checkIdSpacesDown(Component comp, SpaceInfo si) {
0412:                final String compId = comp.getId();
0413:                if (!(comp instanceof  NonFellow)
0414:                        && !ComponentsCtrl.isAutoId(compId)
0415:                        && si.fellows.containsKey(compId))
0416:                    throw new UiException("Not unique in the new ID space: "
0417:                            + compId);
0418:                if (!(comp instanceof  IdSpace))
0419:                    for (Iterator it = comp.getChildren().iterator(); it
0420:                            .hasNext();)
0421:                        checkIdSpacesDown((Component) it.next(), si); //recursive
0422:            }
0423:
0424:            /** Checks comp and its descendants for the specified page. */
0425:            private static void checkIdSpacesDown(Component comp,
0426:                    PageCtrl pageCtrl) {
0427:                final String compId = comp.getId();
0428:                if (!(comp instanceof  NonFellow)
0429:                        && !ComponentsCtrl.isAutoId(compId)
0430:                        && pageCtrl.hasFellow(compId))
0431:                    throw new UiException("Not unique in the ID space of "
0432:                            + pageCtrl + ": " + compId);
0433:                if (!(comp instanceof  IdSpace))
0434:                    for (Iterator it = comp.getChildren().iterator(); it
0435:                            .hasNext();)
0436:                        checkIdSpacesDown((Component) it.next(), pageCtrl); //recursive
0437:            }
0438:
0439:            /** Bind comp to this ID space (owned by this component).
0440:             * Called only if IdSpace is implemented.
0441:             */
0442:            private void bindToIdSpace(Component comp) {
0443:                final String compId = comp.getId();
0444:                _spaceInfo.fellows.put(compId, comp);
0445:            }
0446:
0447:            /** Unbind comp from this ID space (owned by this component).
0448:             * Called only if IdSpace is implemented.
0449:             */
0450:            private void unbindFromIdSpace(String compId) {
0451:                _spaceInfo.fellows.remove(compId);
0452:            }
0453:
0454:            //-- Extra utlities --//
0455:            /** Returns the mold URI based on {@link #getMold}
0456:             * and the molds defined in the component definition
0457:             * ({@link ComponentDefinition}).
0458:             *
0459:             * <p>As of release 3.0.0, it may return a String instance representing
0460:             * the URI, or a {@link ComponentRenderer} instance responsible for
0461:             * redrawing.
0462:             *
0463:             * <p>Used only for component implementation.
0464:             */
0465:            protected Object getMoldURI() {
0466:                return _def.getMoldURI(this , getMold());
0467:            }
0468:
0469:            /** Returns the UI engine based on {@link #_page}'s getDesktop().
0470:             * Don't call this method when _page is null.
0471:             */
0472:            private final UiEngine getThisUiEngine() {
0473:                return ((WebAppCtrl) _page.getDesktop().getWebApp())
0474:                        .getUiEngine();
0475:            }
0476:
0477:            //-- Component --//
0478:            public final Page getPage() {
0479:                return _page;
0480:            }
0481:
0482:            public final Desktop getDesktop() {
0483:                return _page != null ? _page.getDesktop() : null;
0484:            }
0485:
0486:            public void setPage(Page page) {
0487:                if (page != _page)
0488:                    setPageBefore(page, null); //append
0489:            }
0490:
0491:            public void setPageBefore(Page page, Component refRoot) {
0492:                if (refRoot != null
0493:                        && (page == null || refRoot == this 
0494:                                || refRoot.getParent() != null || refRoot
0495:                                .getPage() != page))
0496:                    refRoot = null;
0497:
0498:                if (_parent != null)
0499:                    throw new UiException(
0500:                            "Only the parent of a root component can be changed: "
0501:                                    + this );
0502:
0503:                final boolean samepg = page == _page;
0504:                if (!samepg) {
0505:                    if (page != null) {
0506:                        if (_page != null
0507:                                && _page.getDesktop() != page.getDesktop())
0508:                            throw new UiException(
0509:                                    "The new page must be in the same desktop: "
0510:                                            + page);
0511:                        //Not allow developers to access two desktops simutaneously
0512:                        checkIdSpacesDown(this , (PageCtrl) page);
0513:
0514:                        //No need to check UUID since checkIdSpacesDown covers it
0515:                        //-- a page is an ID space
0516:                    } else { //detach from a page
0517:                        checkDetach(_page);
0518:                    }
0519:
0520:                    if (_page != null)
0521:                        removeFromIdSpacesDown(this );
0522:                }
0523:
0524:                addMoved(_parent, _page, page); //Not depends on UUID
0525:                if (!samepg)
0526:                    setPage0(page); //UUID might be changed here
0527:                if (page != null && (samepg || refRoot != null))
0528:                    ((PageCtrl) page).moveRoot(this , refRoot);
0529:
0530:                if (!samepg && _page != null)
0531:                    addToIdSpacesDown(this );
0532:            }
0533:
0534:            /** Checks whether it is OK to detach the specified page.
0535:             * @param page the page to detach (never null).
0536:             */
0537:            private static void checkDetach(Page page) {
0538:                final Execution exec = Executions.getCurrent();
0539:                if (exec == null)
0540:                    throw new UiException(
0541:                            "You cannot access a desktop other than an event listener");
0542:                if (page.getDesktop() != exec.getDesktop())
0543:                    throw new UiException(
0544:                            "You cannot access components belong to other desktop");
0545:            }
0546:
0547:            /** Called when this component is moved from the specified parent
0548:             * and/or page to the new page.
0549:             *
0550:             * <p>Default: it notifies {@link UiEngine} to update the component
0551:             * at the client (usually remove-and-add).
0552:             *
0553:             * <p>It is designed to let derived classes overriding this method
0554:             * to disable this update. However, you rarely need to override it.
0555:             * One possible but rare case: the component's
0556:             * visual part at the client updates the visual representation
0557:             * at the client and then notify the component at the server
0558:             * to update its children accordingly. In this case, it is redudant
0559:             * if we ask UI Engine to send the updates to client.
0560:             *
0561:             * @param oldparent the parent before moved.
0562:             * The new parent can be found by calling {@link #getParent}.
0563:             * @param oldpg the parent before moved.
0564:             * @param newpg the new page. {@link #getPage} might return
0565:             * the old page.
0566:             */
0567:            protected void addMoved(Component oldparent, Page oldpg, Page newpg) {
0568:                final Desktop dt;
0569:                if (oldpg != null)
0570:                    dt = oldpg.getDesktop();
0571:                else if (newpg != null)
0572:                    dt = newpg.getDesktop();
0573:                else
0574:                    return;
0575:
0576:                ((WebAppCtrl) dt.getWebApp()).getUiEngine().addMoved(this ,
0577:                        oldparent, oldpg, newpg);
0578:            }
0579:
0580:            /** Ses the page without fixing IdSpace
0581:             */
0582:            private void setPage0(Page page) {
0583:                if (page == _page)
0584:                    return; //nothing changed
0585:
0586:                //assert D.OFF || _parent == null || _parent.getPage() == page;
0587:                //detach
0588:                final boolean bRoot = _parent == null;
0589:                if (_page != null) {
0590:                    if (bRoot)
0591:                        ((PageCtrl) _page).removeRoot(this );
0592:                    if (page == null) {
0593:                        ((DesktopCtrl) _page.getDesktop())
0594:                                .removeComponent(this );
0595:                    }
0596:                }
0597:
0598:                final Page oldpage = _page;
0599:                _page = page;
0600:
0601:                if (_page != null) {
0602:                    if (bRoot)
0603:                        ((PageCtrl) _page).addRoot(this ); //Not depends on uuid
0604:                    final Desktop desktop = _page.getDesktop();
0605:                    if (oldpage == null) {
0606:                        if (_uuid == null
0607:                                || _uuid == ComponentsCtrl.ANONYMOUS_ID
0608:                                || desktop.getComponentByUuidIfAny(_uuid) != null)
0609:                            _uuid = nextUuid(desktop);
0610:                        if (_id == null || (this  instanceof  RawId))
0611:                            _id = _uuid;
0612:                        //no need to handle ID space since it is either
0613:                        //anonymous or uuid is not changed
0614:
0615:                        ((DesktopCtrl) desktop).addComponent(this ); //depends on uuid
0616:                    }
0617:
0618:                    onPageAttached(_page, oldpage);
0619:                } else {
0620:                    onPageDetached(oldpage);
0621:                }
0622:
0623:                if (_spaceInfo != null && _parent == null)
0624:                    _spaceInfo.ns.setParent(page != null ? page.getNamespace()
0625:                            : null);
0626:
0627:                //process all children recursively
0628:                for (AbstractComponent p = _first; p != null; p = p._next)
0629:                    p.setPage0(page); //recursive
0630:            }
0631:
0632:            private String nextUuid(Desktop desktop) {
0633:                final IdGenerator idgen = ((WebAppCtrl) desktop.getWebApp())
0634:                        .getIdGenerator();
0635:
0636:                String uuid;
0637:                do {
0638:                    uuid = idgen != null ? idgen.nextComponentUuid(desktop,
0639:                            this ) : null;
0640:                    if (uuid == null)
0641:                        uuid = ((DesktopCtrl) desktop).getNextUuid();
0642:                } while (desktop.getComponentByUuidIfAny(uuid) != null);
0643:                return uuid;
0644:            }
0645:
0646:            public String getId() {
0647:                if (_id == null)
0648:                    _id = getUuid();
0649:                return _id;
0650:            }
0651:
0652:            public void setId(String id) {
0653:                if (id == null || id.length() == 0)
0654:                    throw new UiException("ID cannot be empty");
0655:
0656:                if (!Objects.equals(_id, id)) {
0657:                    if (Names.isReserved(id)
0658:                            || (!(this  instanceof  NonFellow) && ComponentsCtrl
0659:                                    .isAutoId(id)))
0660:                        throw new UiException("Invalid ID: " + id
0661:                                + ". Cause: reserved words not allowed: "
0662:                                + Names.getReservedNames());
0663:
0664:                    final boolean rawId = this  instanceof  RawId;
0665:                    if (rawId
0666:                            && _page != null
0667:                            && _page.getDesktop().getComponentByUuidIfAny(id) != null)
0668:                        throw new UiException(
0669:                                "Replicated ID is not allowed for "
0670:                                        + getClass()
0671:                                        + ": "
0672:                                        + id
0673:                                        + "\nNote: HTML/WML tags, ID must be unique");
0674:
0675:                    checkIdSpaces(this , id);
0676:
0677:                    removeFromIdSpaces(this );
0678:                    if (rawId) { //we have to change UUID
0679:                        if (_page != null) {
0680:                            getThisUiEngine().addUuidChanged(this , false);
0681:                            //called before uuid is changed
0682:                            ((DesktopCtrl) _page.getDesktop())
0683:                                    .removeComponent(this );
0684:                        }
0685:
0686:                        _uuid = _id = id;
0687:
0688:                        if (_page != null) {
0689:                            ((DesktopCtrl) _page.getDesktop())
0690:                                    .addComponent(this );
0691:                            addMoved(_parent, _page, _page);
0692:                        }
0693:                    } else {
0694:                        _id = id;
0695:                    }
0696:                    addToIdSpaces(this );
0697:
0698:                    final Object xc = getExtraCtrl();
0699:                    if ((xc instanceof  ZidRequired)
0700:                            && ((ZidRequired) xc).isZidRequired())
0701:                        smartUpdate("z.zid", _id);
0702:                }
0703:            }
0704:
0705:            public final String getUuid() {
0706:                if (_uuid == null) {
0707:                    final Execution exec = Executions.getCurrent();
0708:                    _uuid = exec == null ? ComponentsCtrl.ANONYMOUS_ID
0709:                            : nextUuid(exec.getDesktop());
0710:                    if (_id == null || (this  instanceof  RawId))
0711:                        _id = _uuid;
0712:                }
0713:                return _uuid;
0714:            }
0715:
0716:            public final IdSpace getSpaceOwner() {
0717:                Component p = this ;
0718:                do {
0719:                    if (p instanceof  IdSpace)
0720:                        return (IdSpace) p;
0721:                } while ((p = p.getParent()) != null);
0722:                return _page;
0723:            }
0724:
0725:            public Component getFellow(String compId) {
0726:                if (this  instanceof  IdSpace) {
0727:                    final Component comp = (Component) _spaceInfo.fellows
0728:                            .get(compId);
0729:                    if (comp == null)
0730:                        if (compId != null && ComponentsCtrl.isAutoId(compId))
0731:                            throw new ComponentNotFoundException(
0732:                                    MZk.AUTO_ID_NOT_LOCATABLE, compId);
0733:                        else
0734:                            throw new ComponentNotFoundException(
0735:                                    "Fellow component not found: " + compId);
0736:                    return comp;
0737:                }
0738:
0739:                final IdSpace idspace = getSpaceOwner();
0740:                if (idspace == null)
0741:                    throw new ComponentNotFoundException(
0742:                            "This component doesn't belong to any ID space: "
0743:                                    + this );
0744:                return idspace.getFellow(compId);
0745:            }
0746:
0747:            public Component getFellowIfAny(String compId) {
0748:                if (this  instanceof  IdSpace)
0749:                    return (Component) _spaceInfo.fellows.get(compId);
0750:
0751:                final IdSpace idspace = getSpaceOwner();
0752:                return idspace == null ? null : idspace.getFellowIfAny(compId);
0753:            }
0754:
0755:            public Component getNextSibling() {
0756:                return _next;
0757:            }
0758:
0759:            public Component getPreviousSibling() {
0760:                return _prev;
0761:            }
0762:
0763:            public Component getFirstChild() {
0764:                return _first;
0765:            }
0766:
0767:            public Component getLastChild() {
0768:                return _last;
0769:            }
0770:
0771:            public Map getAttributes(int scope) {
0772:                switch (scope) {
0773:                case SPACE_SCOPE:
0774:                    if (this  instanceof  IdSpace)
0775:                        return _spaceInfo.attrs;
0776:                    final IdSpace idspace = getSpaceOwner();
0777:                    return idspace instanceof  Page ? ((Page) idspace)
0778:                            .getAttributes()
0779:                            : idspace == null ? Collections.EMPTY_MAP
0780:                                    : ((Component) idspace)
0781:                                            .getAttributes(SPACE_SCOPE);
0782:                case PAGE_SCOPE:
0783:                    return _page != null ? _page.getAttributes()
0784:                            : Collections.EMPTY_MAP;
0785:                case DESKTOP_SCOPE:
0786:                    return _page != null ? _page.getDesktop().getAttributes()
0787:                            : Collections.EMPTY_MAP;
0788:                case SESSION_SCOPE:
0789:                    return _page != null ? _page.getDesktop().getSession()
0790:                            .getAttributes() : Collections.EMPTY_MAP;
0791:                case APPLICATION_SCOPE:
0792:                    return _page != null ? _page.getDesktop().getWebApp()
0793:                            .getAttributes() : Collections.EMPTY_MAP;
0794:                case COMPONENT_SCOPE:
0795:                    return _attrs;
0796:                case REQUEST_SCOPE:
0797:                    final Execution exec = getExecution();
0798:                    if (exec != null)
0799:                        return exec.getAttributes();
0800:                    //fall thru
0801:                default:
0802:                    return Collections.EMPTY_MAP;
0803:                }
0804:            }
0805:
0806:            private final Execution getExecution() {
0807:                return _page != null ? _page.getDesktop().getExecution()
0808:                        : Executions.getCurrent();
0809:            }
0810:
0811:            public Object getAttribute(String name, int scope) {
0812:                return getAttributes(scope).get(name);
0813:            }
0814:
0815:            public Object setAttribute(String name, Object value, int scope) {
0816:                if (value != null) {
0817:                    final Map attrs = getAttributes(scope);
0818:                    if (attrs == Collections.EMPTY_MAP)
0819:                        throw new IllegalStateException("This component, "
0820:                                + this  + ", doesn't belong to the "
0821:                                + Components.scopeToString(scope) + " scope");
0822:                    return attrs.put(name, value);
0823:                } else {
0824:                    return removeAttribute(name, scope);
0825:                }
0826:            }
0827:
0828:            public Object removeAttribute(String name, int scope) {
0829:                final Map attrs = getAttributes(scope);
0830:                if (attrs == Collections.EMPTY_MAP)
0831:                    throw new IllegalStateException(
0832:                            "This component doesn't belong to any ID space: "
0833:                                    + this );
0834:                return attrs.remove(name);
0835:            }
0836:
0837:            public final Map getAttributes() {
0838:                return _attrs;
0839:            }
0840:
0841:            public final Object getAttribute(String name) {
0842:                return _attrs.get(name);
0843:            }
0844:
0845:            public final Object setAttribute(String name, Object value) {
0846:                return value != null ? _attrs.put(name, value) : _attrs
0847:                        .remove(name);
0848:            }
0849:
0850:            public final Object removeAttribute(String name) {
0851:                return _attrs.remove(name);
0852:            }
0853:
0854:            public void setVariable(String name, Object val, boolean local) {
0855:                getNamespace().setVariable(name, val, local);
0856:            }
0857:
0858:            public boolean containsVariable(String name, boolean local) {
0859:                return getNamespace().containsVariable(name, local);
0860:            }
0861:
0862:            public Object getVariable(String name, boolean local) {
0863:                return getNamespace().getVariable(name, local);
0864:            }
0865:
0866:            public void unsetVariable(String name, boolean local) {
0867:                getNamespace().unsetVariable(name, local);
0868:            }
0869:
0870:            public Component getParent() {
0871:                return _parent;
0872:            }
0873:
0874:            public void setParent(Component parent) {
0875:                if (_parent == parent)
0876:                    return; //nothing changed
0877:
0878:                checkParentChild(parent, this );
0879:
0880:                final boolean idSpaceChanged = parent != null ? parent
0881:                        .getSpaceOwner() != (_parent != null ? _parent
0882:                        .getSpaceOwner() : _page) : _page != null;
0883:
0884:                if (idSpaceChanged)
0885:                    removeFromIdSpacesDown(this );
0886:
0887:                //call removeChild and clear _parent
0888:                final AbstractComponent op = _parent;
0889:                if (op != null) {
0890:                    if (!op.inRemoving(this )) {
0891:                        op.markRemoving(this , true);
0892:                        try {
0893:                            op.removeChild(this ); //spec: call back removeChild
0894:                        } finally {
0895:                            op.markRemoving(this , false);
0896:                        }
0897:                    }
0898:                    _parent = null; //op.removeChild assumes _parent not changed yet
0899:                } else {
0900:                    if (_page != null)
0901:                        ((PageCtrl) _page).removeRoot(this ); //Not depends on uuid
0902:                }
0903:
0904:                //call insertBefore and set _parent
0905:                if (parent != null) {
0906:                    final AbstractComponent np = (AbstractComponent) parent;
0907:                    if (!np.inAdding(this )) {
0908:                        np.markAdding(this , true);
0909:                        try {
0910:                            np.insertBefore(this , null); //spec: call back inserBefore
0911:                        } finally {
0912:                            np.markAdding(this , false);
0913:                        }
0914:                    }
0915:                    _parent = np; //np.insertBefore assumes _parent not changed yet
0916:                } //if parent == null, assume no page at all (so no addRoot)
0917:
0918:                //correct _page
0919:                final Page newpg = _parent != null ? _parent.getPage() : null;
0920:                addMoved(op, _page, newpg); //Not depends on UUID
0921:                setPage0(newpg); //UUID might be changed here
0922:
0923:                if (_spaceInfo != null) //ID space owner
0924:                    _spaceInfo.ns.setParent(_parent != null ? _parent
0925:                            .getNamespace() : null);
0926:                if (idSpaceChanged)
0927:                    addToIdSpacesDown(this ); //called after setPage
0928:            }
0929:
0930:            /** Returns whether the child is being removed.
0931:             */
0932:            private boolean inRemoving(Component child) {
0933:                return _rming != null && _rming.contains(child);
0934:            }
0935:
0936:            /** Sets if the child is being removed.
0937:             */
0938:            private void markRemoving(Component child, boolean set) {
0939:                if (set) {
0940:                    if (_rming == null)
0941:                        _rming = new HashSet(2);
0942:                    _rming.add(child);
0943:                } else {
0944:                    if (_rming != null && _rming.remove(child)
0945:                            && _rming.isEmpty())
0946:                        _rming = null;
0947:                }
0948:            }
0949:
0950:            /** Returns whether the child is being added.
0951:             */
0952:            private boolean inAdding(Component child) {
0953:                return _adding != null && _adding.contains(child);
0954:            }
0955:
0956:            /** Sets if the child is being added.
0957:             */
0958:            private void markAdding(Component child, boolean set) {
0959:                if (set) {
0960:                    if (_adding == null)
0961:                        _adding = new HashSet(2);
0962:                    _adding.add(child);
0963:                } else {
0964:                    if (_adding != null && _adding.remove(child)
0965:                            && _adding.isEmpty())
0966:                        _adding = null;
0967:                }
0968:            }
0969:
0970:            /**
0971:             * @param parent the parent (will-be). It may be null.
0972:             * @param child the child (will-be). It cannot be null.
0973:             */
0974:            private static void checkParentChild(Component parent,
0975:                    Component child) throws UiException {
0976:                if (parent != null) {
0977:                    if (((AbstractComponent) parent).inAdding(child))
0978:                        return; //check only once
0979:
0980:                    if (Components.isAncestor(child, parent))
0981:                        throw new UiException(
0982:                                "A child cannot be a parent of its ancestor: "
0983:                                        + child);
0984:                    if (!parent.isChildable())
0985:                        throw new UiException(parent
0986:                                + " doesn't allow any child");
0987:
0988:                    final Page parentpg = parent.getPage(), childpg = child
0989:                            .getPage();
0990:                    if (parentpg != null && childpg != null
0991:                            && parentpg.getDesktop() != childpg.getDesktop())
0992:                        throw new UiException(
0993:                                "The parent and child must be in the same desktop: "
0994:                                        + parent);
0995:
0996:                    final Component oldparent = child.getParent();
0997:                    if (parent.getSpaceOwner() != (oldparent != null ? oldparent
0998:                            .getSpaceOwner()
0999:                            : childpg))
1000:                        checkIdSpacesDown(child, parent);
1001:                } else {
1002:                    final Page childpg = child.getPage();
1003:                    if (childpg != null)
1004:                        checkDetach(childpg);
1005:                }
1006:            }
1007:
1008:            public boolean insertBefore(Component newChild, Component refChild) {
1009:                checkParentChild(this , newChild);
1010:
1011:                if (refChild != null && refChild.getParent() != this )
1012:                    refChild = null;
1013:
1014:                final AbstractComponent nc = (AbstractComponent) newChild;
1015:                final boolean moved = nc._parent == this ; //moved in the same parent
1016:                if (moved) {
1017:                    if (nc._next == refChild)
1018:                        return false; //nothing changed
1019:                    nc.addMoved(this , _page, _page);
1020:
1021:                    //detach from original place
1022:                    setNext(nc._prev, nc._next);
1023:                    setPrev(nc._next, nc._prev);
1024:                } else { //new added
1025:                    //Note: call setParent to detach nc from old parent, if any,
1026:                    //before maintaining nc's _next, _prev...
1027:                    if (!inAdding(nc)) {
1028:                        markAdding(nc, true);
1029:                        try {
1030:                            nc.setParent(this ); //spec: callback setParent
1031:                        } finally {
1032:                            markAdding(nc, false);
1033:                        }
1034:                    } else {
1035:                        nc._parent = this ;
1036:                        //Set it since deriving class might assume parent is correct
1037:                        //after insertBefore. For example, Tabs.insertBefore().
1038:                        //
1039:                        //However, we don't call setPage0 and other here,
1040:                        //since the codes will become too complex.
1041:                        //In other words, when super.insertBefore() returns in a
1042:                        //deriving class, _parent is correct but _page may or may not
1043:                    }
1044:                }
1045:
1046:                if (refChild != null) {
1047:                    final AbstractComponent ref = (AbstractComponent) refChild;
1048:                    setNext(nc, ref);
1049:                    setPrev(nc, ref._prev);
1050:                    setNext(ref._prev, nc);
1051:                    setPrev(ref, nc);
1052:                } else {
1053:                    if (_last == null) {
1054:                        _first = _last = nc;
1055:                        nc._next = nc._prev = null;
1056:                    } else {
1057:                        _last._next = nc;
1058:                        nc._prev = _last;
1059:                        nc._next = null;
1060:                        _last = nc;
1061:                    }
1062:                }
1063:
1064:                ++_modCntChd;
1065:                if (!moved) { //new added
1066:                    ++_nChild;
1067:                    onChildAdded(nc);
1068:                }
1069:                return true;
1070:            }
1071:
1072:            private final void setNext(AbstractComponent comp,
1073:                    AbstractComponent next) {
1074:                if (comp != null)
1075:                    comp._next = next;
1076:                else
1077:                    _first = next;
1078:            }
1079:
1080:            private final void setPrev(AbstractComponent comp,
1081:                    AbstractComponent prev) {
1082:                if (comp != null)
1083:                    comp._prev = prev;
1084:                else
1085:                    _last = prev;
1086:            }
1087:
1088:            /** Appends a child to the end of all children.
1089:             * It calls {@link #insertBefore} with refChild to be null.
1090:             * Derives cannot override this method, and they shall override
1091:             * {@link #insertBefore} instead.
1092:             */
1093:            public final boolean appendChild(Component child) { //Yes, final; see below
1094:                return insertBefore(child, null); //NOTE: we must go thru insertBefore
1095:                //such that deriving is easy to override
1096:            }
1097:
1098:            public boolean removeChild(Component child) {
1099:                if (child.getParent() != this )
1100:                    return false; //nothing to do
1101:
1102:                final AbstractComponent oc = (AbstractComponent) child;
1103:                setNext(oc._prev, oc._next);
1104:                setPrev(oc._next, oc._prev);
1105:                oc._next = oc._prev = null;
1106:
1107:                if (!inRemoving(oc)) {
1108:                    markRemoving(oc, true);
1109:                    try {
1110:                        oc.setParent(null); //spec: call back setParent
1111:                    } finally {
1112:                        markRemoving(oc, false);
1113:                    }
1114:                } else {
1115:                    oc._parent = null;
1116:                    //Correct it since deriving class might assume parent is
1117:                    //correct after insertBefore() returns.
1118:                    //refer to insertBefore for more info.
1119:                }
1120:
1121:                ++_modCntChd;
1122:                --_nChild;
1123:                onChildRemoved(child);
1124:                return true;
1125:            }
1126:
1127:            /** Default: return true (allows to have children).
1128:             */
1129:            public boolean isChildable() {
1130:                return true;
1131:            }
1132:
1133:            public List getChildren() {
1134:                return _apiChildren;
1135:            }
1136:
1137:            /** Returns the root of the specified component.
1138:             */
1139:            public Component getRoot() {
1140:                for (Component comp = this ;;) {
1141:                    final Component parent = comp.getParent();
1142:                    if (parent == null)
1143:                        return comp;
1144:                    comp = parent;
1145:                }
1146:            }
1147:
1148:            public boolean isVisible() {
1149:                return _visible;
1150:            }
1151:
1152:            public boolean setVisible(boolean visible) {
1153:                final boolean old = _visible;
1154:                if (old != visible) {
1155:                    _visible = visible;
1156:                    smartUpdate("visibility", _visible);
1157:                }
1158:                return old;
1159:            }
1160:
1161:            public void invalidate() {
1162:                if (_page != null)
1163:                    getThisUiEngine().addInvalidate(this );
1164:            }
1165:
1166:            public void response(String key, AuResponse response) {
1167:                //if response not depend on this component, it must be generated
1168:                if (_page != null) {
1169:                    getThisUiEngine().addResponse(key, response);
1170:                } else if (response.getDepends() != this ) {
1171:                    final Execution exec = Executions.getCurrent();
1172:                    if (exec != null)
1173:                        ((WebAppCtrl) exec.getDesktop().getWebApp())
1174:                                .getUiEngine().addResponse(key, response);
1175:                }
1176:            }
1177:
1178:            public void smartUpdate(String attr, String value) {
1179:                if (_page != null)
1180:                    getThisUiEngine().addSmartUpdate(this , attr, value);
1181:            }
1182:
1183:            /** Smart-updates a property with a deferred value.
1184:             * A deferred value is used to encapsulate a value that shall be retrieved
1185:             * only in the rendering phase.
1186:             *
1187:             * @since 3.0.1
1188:             */
1189:            public void smartUpdateDeferred(String attr, DeferredValue value) {
1190:                if (_page != null)
1191:                    getThisUiEngine().addSmartUpdate(this , attr, value);
1192:            }
1193:
1194:            /** A special smart-update that update a value in int.
1195:             * <p>It will invoke {@link #smartUpdate(String,String)} to update
1196:             * the attribute eventually.
1197:             */
1198:            public void smartUpdate(String attr, int value) {
1199:                smartUpdate(attr, Integer.toString(value));
1200:            }
1201:
1202:            /** A special smart-update that update a value in boolean.
1203:             * <p>It will invoke {@link #smartUpdate(String,String)} to update
1204:             * the attribute eventually.
1205:             */
1206:            public void smartUpdate(String attr, boolean value) {
1207:                smartUpdate(attr, Boolean.toString(value));
1208:            }
1209:
1210:            public void detach() {
1211:                if (getParent() != null)
1212:                    setParent(null);
1213:                else
1214:                    setPage(null);
1215:            }
1216:
1217:            /** Default: does nothing.
1218:             * @see Component#onChildAdded
1219:             */
1220:            public void onChildAdded(Component child) {
1221:            }
1222:
1223:            /** Default: does nothing.
1224:             * @see Component#onChildRemoved
1225:             */
1226:            public void onChildRemoved(Component child) {
1227:            }
1228:
1229:            /** Default: handles special event listeners.
1230:             * @see Component#onPageAttached
1231:             * @since 3.0.0
1232:             */
1233:            public void onPageAttached(Page newpage, Page oldpage) {
1234:                if (oldpage == null) //new added
1235:                    onListenerChanged(newpage.getDesktop(), true);
1236:            }
1237:
1238:            /** Default: handles special event listeners.
1239:             * @see Component#onPageDetached
1240:             * @since 3.0.0
1241:             */
1242:            public void onPageDetached(Page page) {
1243:                onListenerChanged(page.getDesktop(), false);
1244:            }
1245:
1246:            /** Default: null (no propagation at all).
1247:             */
1248:            public Component getPropagatee(String evtnm) {
1249:                return null;
1250:            }
1251:
1252:            /** Returns the mold used to render this component.
1253:             * Default: "default"
1254:             */
1255:            public final String getMold() {
1256:                return _mold;
1257:            }
1258:
1259:            public void setMold(String mold) {
1260:                if (mold == null || mold.length() == 0)
1261:                    mold = "default";
1262:                if (!Objects.equals(_mold, mold)) {
1263:                    if (!_def.hasMold(mold))
1264:                        throw new UiException("Unknown mold: " + mold
1265:                                + ", while allowed include "
1266:                                + _def.getMoldNames());
1267:                    _mold = mold;
1268:                    invalidate();
1269:                }
1270:            }
1271:
1272:            //-- in the redrawing phase --//
1273:            /** Redraws this component.
1274:             * This method implements the mold mechanism.
1275:             * <ol>
1276:             * <li>It first invokes {@link #getMoldURI} to retrieve the mold
1277:             * to redraw. The mold is either an URI (String) or a
1278:             * {@link ComponentRenderer} instance.
1279:             * <li>If URI, it invokes {@link Execution#include} to generate
1280:             * the output.</li>
1281:             * <li>If a {@link ComponentRenderer} instance, {@link ComponentRenderer#render}
1282:             * is called to generate the output.</li>
1283:             * </ul>
1284:             */
1285:            public void redraw(Writer out) throws IOException {
1286:                final Object mold = getMoldURI();
1287:                if (mold instanceof  ComponentRenderer) {
1288:                    ((ComponentRenderer) mold).render(this , out != null ? out
1289:                            : ZkFns.getCurrentOut());
1290:                } else {
1291:                    final Map attrs = new HashMap(2);
1292:                    attrs.put("self", this );
1293:                    getExecution().include(out, (String) mold, attrs,
1294:                            Execution.PASS_THRU_ATTR);
1295:                }
1296:            }
1297:
1298:            /* Default: does nothing.
1299:             */
1300:            public void onDrawNewChild(Component child, StringBuffer out)
1301:                    throws IOException {
1302:            }
1303:
1304:            /** Returns whether to send back the request of the specified event
1305:             * immediately -- i.e., non-deferrable.
1306:             * Returns true if you want the component (on the server)
1307:             * to process the event immediately.
1308:             *
1309:             * <p>Default: return true if any non-deferable event listener of
1310:             * the specified event is found. In other words, it returns
1311:             * {@link Events#isListened} with asap = true.
1312:             *
1313:             * <p>This method is moved from {@link HtmlBasedComponent} to
1314:             * {@link AbstractComponent} since 3.0.0.
1315:             *
1316:             * @param evtnm the event name, such as onClick
1317:             * @since 3.0.0
1318:             */
1319:            protected boolean isAsapRequired(String evtnm) {
1320:                return Events.isListened(this , evtnm, true);
1321:            }
1322:
1323:            /** Appends an attribute for the specified event name, say, onChange,
1324:             * if a non-deferrable listener is registered.
1325:             * The format of the generated attribute is as follows:
1326:             * <code>onChange="true"</code>.
1327:             *
1328:             * <p>This method is moved from {@link HtmlBasedComponent} to
1329:             * {@link AbstractComponent} since 3.0.0.
1330:             *
1331:             * @param sb the string buffer to hold the HTML attribute. If null and
1332:             * {@link #isAsapRequired} is true, a string buffer is created and returned.
1333:             * @param evtnm the event name, such as onClick
1334:             * @return the string buffer. If sb is null and {@link #isAsapRequired}
1335:             * returns false, null is returned.
1336:             * If the caller passed non-null sb, the returned value must be the same
1337:             * as sb (so it usually ignores the returned value).
1338:             * @since 3.0.0
1339:             */
1340:            protected StringBuffer appendAsapAttr(StringBuffer sb, String evtnm) {
1341:                if (isAsapRequired(evtnm)) {
1342:                    if (sb == null)
1343:                        sb = new StringBuffer(80);
1344:                    HTMLs.appendAttribute(sb, getAttrOfEvent(evtnm), true);
1345:                }
1346:                return sb;
1347:            }
1348:
1349:            private static String getAttrOfEvent(String evtnm) {
1350:                return Events.ON_CLICK.equals(evtnm) ? "z.lfclk"
1351:                        : Events.ON_RIGHT_CLICK.equals(evtnm) ? "z.rtclk"
1352:                                : Events.ON_DOUBLE_CLICK.equals(evtnm) ? "z.dbclk"
1353:                                        : "z." + evtnm;
1354:            }
1355:
1356:            public boolean addEventListener(String evtnm, EventListener listener) {
1357:                if (evtnm == null || listener == null)
1358:                    throw new IllegalArgumentException("null");
1359:                if (!Events.isValid(evtnm))
1360:                    throw new IllegalArgumentException("Invalid event name: "
1361:                            + evtnm);
1362:
1363:                final boolean asap = isAsapRequired(evtnm);
1364:
1365:                if (_listeners == null)
1366:                    _listeners = new HashMap(8);
1367:
1368:                List l = (List) _listeners.get(evtnm);
1369:                if (l != null) {
1370:                    for (Iterator it = l.iterator(); it.hasNext();) {
1371:                        final EventListener li = (EventListener) it.next();
1372:                        if (listener.equals(li))
1373:                            return false;
1374:                    }
1375:                } else {
1376:                    _listeners.put(evtnm, l = new LinkedList());
1377:                }
1378:                l.add(listener);
1379:
1380:                final Desktop desktop = getDesktop();
1381:                if (desktop != null) {
1382:                    if (Events.ON_CLIENT_INFO.equals(evtnm))
1383:                        response("clientInfo", new AuClientInfo(desktop));
1384:                    if (Events.ON_PIGGYBACK.equals(evtnm))
1385:                        ((DesktopCtrl) desktop).onPiggybackListened(this , true);
1386:
1387:                    if (!asap && isAsapRequired(evtnm))
1388:                        smartUpdate(getAttrOfEvent(evtnm), "true");
1389:                }
1390:                return true;
1391:            }
1392:
1393:            public boolean removeEventListener(String evtnm,
1394:                    EventListener listener) {
1395:                if (evtnm == null || listener == null)
1396:                    throw new IllegalArgumentException("null");
1397:
1398:                if (_listeners != null) {
1399:                    final boolean asap = isAsapRequired(evtnm);
1400:                    final List l = (List) _listeners.get(evtnm);
1401:                    if (l != null) {
1402:                        for (Iterator it = l.iterator(); it.hasNext();) {
1403:                            final EventListener li = (EventListener) it.next();
1404:                            if (listener.equals(li)) {
1405:                                if (l.size() == 1)
1406:                                    _listeners.remove(evtnm);
1407:                                else
1408:                                    it.remove();
1409:
1410:                                final Desktop desktop = getDesktop();
1411:                                if (desktop != null) {
1412:                                    onListenerChanged(desktop, false);
1413:
1414:                                    if (asap && !isAsapRequired(evtnm))
1415:                                        smartUpdate(getAttrOfEvent(evtnm), null);
1416:                                }
1417:                                return true;
1418:                            }
1419:                        }
1420:                    }
1421:                }
1422:                return false;
1423:            }
1424:
1425:            public boolean addForward(String orgEvent, Component target,
1426:                    String targetEvent) {
1427:                return addForward0(orgEvent, target, targetEvent);
1428:            }
1429:
1430:            public boolean addForward(String orgEvent, String targetPath,
1431:                    String targetEvent) {
1432:                return addForward0(orgEvent, targetPath, targetEvent);
1433:            }
1434:
1435:            /**
1436:             * @param target the target. It is either a component, or a string,
1437:             * which is used internal for implementing {@link #writeObject}
1438:             */
1439:            private boolean addForward0(String orgEvent, Object target,
1440:                    String targetEvent) {
1441:                if (orgEvent == null)
1442:                    orgEvent = "onClick";
1443:                else if (!Events.isValid(orgEvent))
1444:                    throw new IllegalArgumentException("Illegal event name: "
1445:                            + orgEvent);
1446:                if (targetEvent == null)
1447:                    targetEvent = orgEvent;
1448:                else if (!Events.isValid(targetEvent))
1449:                    throw new IllegalArgumentException("Illegal event name: "
1450:                            + targetEvent);
1451:
1452:                if (_forwards == null)
1453:                    _forwards = new HashMap(4);
1454:
1455:                Object[] info = (Object[]) _forwards.get(orgEvent);
1456:                final List fwds;
1457:                if (info != null) {
1458:                    fwds = (List) info[1];
1459:                    for (Iterator it = fwds.iterator(); it.hasNext();) {
1460:                        final Object[] fwd = (Object[]) it.next();
1461:                        if (Objects.equals(fwd[0], target)
1462:                                && Objects.equals(fwd[1], targetEvent)) //found
1463:                            return false;
1464:                    }
1465:                } else {
1466:                    final ForwardListener listener = new ForwardListener(
1467:                            orgEvent);
1468:                    addEventListener(orgEvent, listener);
1469:                    info = new Object[] { listener, fwds = new LinkedList() };
1470:                    _forwards.put(orgEvent, info);
1471:                }
1472:
1473:                fwds.add(new Object[] { target, targetEvent });
1474:                return true;
1475:            }
1476:
1477:            public boolean removeForward(String orgEvent, Component target,
1478:                    String targetEvent) {
1479:                return removeForward0(orgEvent, target, targetEvent);
1480:            }
1481:
1482:            public boolean removeForward(String orgEvent, String targetPath,
1483:                    String targetEvent) {
1484:                return removeForward0(orgEvent, targetPath, targetEvent);
1485:            }
1486:
1487:            private boolean removeForward0(String orgEvent, Object target,
1488:                    String targetEvent) {
1489:                if (_forwards != null) {
1490:                    final Object[] info = (Object[]) _forwards.get(orgEvent);
1491:                    if (info != null) {
1492:                        final List fwds = (List) info[1];
1493:                        for (Iterator it = fwds.iterator(); it.hasNext();) {
1494:                            final Object[] fwd = (Object[]) it.next();
1495:                            if (Objects.equals(fwd[0], target)
1496:                                    && Objects.equals(fwd[1], targetEvent)) { //found
1497:                                it.remove(); //remove it
1498:
1499:                                if (fwds.isEmpty()) { //no more event
1500:                                    _forwards.remove(orgEvent);
1501:                                    removeEventListener(orgEvent,
1502:                                            (EventListener) info[0]);
1503:                                }
1504:                                return true;
1505:                            }
1506:                        }
1507:                    }
1508:                }
1509:                return false;
1510:            }
1511:
1512:            public Namespace getNamespace() {
1513:                if (this  instanceof  IdSpace)
1514:                    return _spaceInfo.ns;
1515:
1516:                final IdSpace idspace = getSpaceOwner();
1517:                return idspace instanceof  Page ? ((Page) idspace)
1518:                        .getNamespace() : idspace == null ? null
1519:                        : ((Component) idspace).getNamespace();
1520:            }
1521:
1522:            public boolean isListenerAvailable(String evtnm, boolean asap) {
1523:                if (_listeners != null) {
1524:                    final List l = (List) _listeners.get(evtnm);
1525:                    if (l != null) {
1526:                        if (!asap)
1527:                            return !l.isEmpty();
1528:
1529:                        for (Iterator it = l.iterator(); it.hasNext();) {
1530:                            final EventListener li = (EventListener) it.next();
1531:                            if (!(li instanceof  Deferrable)
1532:                                    || !(((Deferrable) li).isDeferrable()))
1533:                                return true;
1534:                        }
1535:                    }
1536:                }
1537:                return false;
1538:            }
1539:
1540:            public Iterator getListenerIterator(String evtnm) {
1541:                if (_listeners != null) {
1542:                    final List l = (List) _listeners.get(evtnm);
1543:                    if (l != null)
1544:                        return new ListenerIterator(l);
1545:                }
1546:                return CollectionsX.EMPTY_ITERATOR;
1547:            }
1548:
1549:            public void applyProperties() {
1550:                _def.applyProperties(this );
1551:            }
1552:
1553:            public ComponentDefinition getDefinition() {
1554:                return _def;
1555:            }
1556:
1557:            //-- ComponentCtrl --//
1558:            public void setComponentDefinition(ComponentDefinition compdef) {
1559:                if (compdef == null)
1560:                    throw new IllegalArgumentException("null");
1561:                if (!compdef.isInstance(this ))
1562:                    throw new IllegalArgumentException("Incompatible "
1563:                            + compdef + " for " + this );
1564:                _def = compdef;
1565:            }
1566:
1567:            public ZScript getEventHandler(String evtnm) {
1568:                final EventHandler evthd = _evthds != null ? _evthds.get(this ,
1569:                        evtnm) : null;
1570:                return evthd != null ? evthd.getZScript() : null;
1571:            }
1572:
1573:            public void addSharedEventHandlerMap(EventHandlerMap evthds) {
1574:                if (evthds != null && !evthds.isEmpty()) {
1575:                    unshareEventHandlerMap(false);
1576:                    if (_evthds == null) {
1577:                        _evthds = evthds;
1578:                        _evthdsShared = true;
1579:                    } else {
1580:                        _evthds.addAll(evthds);
1581:                    }
1582:
1583:                    final Desktop desktop = getDesktop();
1584:                    if (desktop != null)
1585:                        onListenerChanged(desktop, true);
1586:                }
1587:            }
1588:
1589:            public Set getEventHandlerNames() {
1590:                return _evthds != null ? _evthds.getEventNames()
1591:                        : Collections.EMPTY_SET;
1592:            }
1593:
1594:            private void onListenerChanged(Desktop desktop, boolean listen) {
1595:                if (listen) {
1596:                    if (Events.isListened(this , Events.ON_CLIENT_INFO, false)) //asap+deferrable
1597:                        response("clientInfo", new AuClientInfo(desktop));
1598:                    //We always fire event not a root, since we don't like to
1599:                    //check when setParent or setPage is called
1600:                    if (Events.isListened(this , Events.ON_PIGGYBACK, false))
1601:                        ((DesktopCtrl) desktop).onPiggybackListened(this , true);
1602:                } else {
1603:                    if (!Events.isListened(this , Events.ON_PIGGYBACK, false))
1604:                        ((DesktopCtrl) desktop)
1605:                                .onPiggybackListened(this , false);
1606:                }
1607:            }
1608:
1609:            public void addEventHandler(String name, EventHandler evthd) {
1610:                if (name == null || evthd == null)
1611:                    throw new IllegalArgumentException(
1612:                            "name and evthd required");
1613:
1614:                unshareEventHandlerMap(true);
1615:                _evthds.add(name, evthd);
1616:            }
1617:
1618:            /** Clones the shared event handlers, if shared.
1619:             * @param autocreate whether to create an event handler map if not available.
1620:             */
1621:            private void unshareEventHandlerMap(boolean autocreate) {
1622:                if (_evthdsShared) {
1623:                    _evthds = (EventHandlerMap) _evthds.clone();
1624:                    _evthdsShared = false;
1625:                } else if (autocreate && _evthds == null) {
1626:                    _evthds = new EventHandlerMap();
1627:                }
1628:            }
1629:
1630:            public Annotation getAnnotation(String annotName) {
1631:                return _annots != null ? _annots.getAnnotation(annotName)
1632:                        : null;
1633:            }
1634:
1635:            public Annotation getAnnotation(String propName, String annotName) {
1636:                return _annots != null ? _annots.getAnnotation(propName,
1637:                        annotName) : null;
1638:            }
1639:
1640:            public Collection getAnnotations() {
1641:                return _annots != null ? _annots.getAnnotations()
1642:                        : Collections.EMPTY_LIST;
1643:            }
1644:
1645:            public Collection getAnnotations(String propName) {
1646:                return _annots != null ? _annots.getAnnotations(propName)
1647:                        : Collections.EMPTY_LIST;
1648:            }
1649:
1650:            public List getAnnotatedPropertiesBy(String annotName) {
1651:                return _annots != null ? _annots
1652:                        .getAnnotatedPropertiesBy(annotName)
1653:                        : Collections.EMPTY_LIST;
1654:            }
1655:
1656:            public List getAnnotatedProperties() {
1657:                return _annots != null ? _annots.getAnnotatedProperties()
1658:                        : Collections.EMPTY_LIST;
1659:            }
1660:
1661:            public void addSharedAnnotationMap(AnnotationMap annots) {
1662:                if (annots != null && !annots.isEmpty()) {
1663:                    unshareAnnotationMap(false);
1664:                    if (_annots == null) {
1665:                        _annots = annots;
1666:                        _annotsShared = true;
1667:                    } else {
1668:                        _annots.addAll(annots);
1669:                    }
1670:                }
1671:            }
1672:
1673:            public void addAnnotation(String annotName, Map annotAttrs) {
1674:                unshareAnnotationMap(true);
1675:                _annots.addAnnotation(annotName, annotAttrs);
1676:            }
1677:
1678:            public void addAnnotation(String propName, String annotName,
1679:                    Map annotAttrs) {
1680:                unshareAnnotationMap(true);
1681:                _annots.addAnnotation(propName, annotName, annotAttrs);
1682:            }
1683:
1684:            /** Clones the shared annotations, if shared.
1685:             * @param autocreate whether to create an annotation map if not available.
1686:             */
1687:            private void unshareAnnotationMap(boolean autocreate) {
1688:                if (_annotsShared) {
1689:                    _annots = (AnnotationMap) _annots.clone();
1690:                    _annotsShared = false;
1691:                } else if (autocreate && _annots == null) {
1692:                    _annots = new AnnotationMap();
1693:                }
1694:            }
1695:
1696:            public void sessionWillPassivate(Page page) {
1697:                //nothing to do
1698:            }
1699:
1700:            public void sessionDidActivate(Page page) {
1701:                sessionDidActivate0(page, this , true);
1702:            }
1703:
1704:            /** 
1705:             * @param pageLevelIdSpace whether this component's ID space is
1706:             * at the page level.
1707:             */
1708:            private static void sessionDidActivate0(Page page,
1709:                    AbstractComponent comp, boolean pageLevelIdSpace) {
1710:                comp._page = page;
1711:
1712:                //Note: we need only to fix the first-level spaceInfo.
1713:                //Others are handled by readObject
1714:                if (pageLevelIdSpace && comp._spaceInfo != null) {
1715:                    pageLevelIdSpace = false;
1716:                    comp._spaceInfo.ns.setParent(page.getNamespace());
1717:                }
1718:
1719:                for (AbstractComponent p = comp._first; p != null; p = p._next) {
1720:                    sessionDidActivate0(page, p, pageLevelIdSpace); //recursive
1721:                }
1722:            }
1723:
1724:            /** Returns the extra controls that tell ZK how to handle this component
1725:             * specially.
1726:             * It is used only by component developers.
1727:             *
1728:             * <p>It is simpler to override {@link #newExtraCtrl} instead of this.
1729:             * By use of {@link #newExtraCtrl}, you don't need to care of
1730:             * cloning and serialization.
1731:             *
1732:             * <p>Default: return the object being created by {@link #newExtraCtrl},
1733:             * if any.
1734:             *
1735:             * @see ComponentCtrl#getExtraCtrl
1736:             */
1737:            public Object getExtraCtrl() {
1738:                if (_xtrl == null)
1739:                    _xtrl = newExtraCtrl();
1740:                //3.0.3: create as late as possible so component has a chance
1741:                //to customize which object to instantiate
1742:                return _xtrl;
1743:            }
1744:
1745:            /** Used by {@link #getExtraCtrl} to create a client control.
1746:             * It is used only by component developers.
1747:             *
1748:             * <p>Default: return null.
1749:             *
1750:             * <p>To provide extra controls, it is simpler to override this method
1751:             * instead of {@link #getExtraCtrl}.
1752:             * By use of {@link #newExtraCtrl}, you don't need to care of
1753:             * cloning and serialization.
1754:             */
1755:            protected Object newExtraCtrl() {
1756:                return null;
1757:            }
1758:
1759:            /** Notifies that an {@link WrongValueException} instance is thrown,
1760:             * and {@link WrongValueException#getComponent} is this component.
1761:             * It is a callback and the component can store the error message,
1762:             * show up the custom information, or even 'eat' the exception.
1763:             *
1764:             * <p>Default: does nothing but returns ex.
1765:             *
1766:             * @param ex the exception being thrown (never null)
1767:             * @return the exception to throw, or null to ignore the exception
1768:             * In most cases, just return ex
1769:             * @since 2.4.0
1770:             */
1771:            public WrongValueException onWrongValue(WrongValueException ex) {
1772:                return ex;
1773:            }
1774:
1775:            //-- Object --//
1776:            public String toString() {
1777:                final String clsnm = getClass().getName();
1778:                final int j = clsnm.lastIndexOf('.');
1779:                return "<"
1780:                        + clsnm.substring(j + 1)
1781:                        + ' '
1782:                        + (_id == null || ComponentsCtrl.isAutoId(_id) ? _uuid
1783:                                : _id) + '>';
1784:            }
1785:
1786:            public final boolean equals(Object o) { //no more override
1787:                return this  == o;
1788:            }
1789:
1790:            /** Holds info shared of the same ID space. */
1791:            private static class SpaceInfo {
1792:                private Map attrs = new HashMap(8);
1793:                //don't create it dynamically because _ip bind it at constructor
1794:                private SimpleNamespace ns;
1795:                /** A map of ((String id, Component fellow). */
1796:                private Map fellows = new HashMap(32);
1797:
1798:                private SpaceInfo(Component owner) {
1799:                    ns = new SimpleNamespace(owner);
1800:                    init(owner);
1801:                }
1802:
1803:                private SpaceInfo(Component owner, SimpleNamespace from) {
1804:                    ns = new SimpleNamespace(owner);
1805:                    ns.copy(from);
1806:                    init(owner);
1807:                }
1808:
1809:                private void init(Component owner) {
1810:                    ns.setVariable("spaceScope", attrs, true);
1811:                    ns.setVariable("spaceOwner", owner, true);
1812:                }
1813:            }
1814:
1815:            private class ChildIter implements  ListIterator {
1816:                private AbstractComponent _p, _lastRet;
1817:                private int _j;
1818:                private int _modCntSnap;
1819:
1820:                private ChildIter(int index) {
1821:                    if (index < 0 || index > _nChild)
1822:                        throw new IndexOutOfBoundsException("Index: " + index
1823:                                + ", Size: " + _nChild);
1824:
1825:                    if (index < (_nChild >> 1)) {
1826:                        _p = _first;
1827:                        for (_j = 0; _j < index; _j++)
1828:                            _p = _p._next;
1829:                    } else {
1830:                        _p = null; //means the end of the list
1831:                        for (_j = _nChild; _j > index; _j--)
1832:                            _p = _p != null ? _p._prev : _last;
1833:                    }
1834:
1835:                    _modCntSnap = _modCntChd;
1836:                }
1837:
1838:                public boolean hasNext() {
1839:                    checkComodification();
1840:                    return _j < _nChild;
1841:                }
1842:
1843:                public Object next() {
1844:                    if (_j >= _nChild)
1845:                        throw new java.util.NoSuchElementException();
1846:                    checkComodification();
1847:
1848:                    _lastRet = _p;
1849:                    _p = _p._next;
1850:                    _j++;
1851:                    return _lastRet;
1852:                }
1853:
1854:                public boolean hasPrevious() {
1855:                    checkComodification();
1856:                    return _j > 0;
1857:                }
1858:
1859:                public Object previous() {
1860:                    if (_j <= 0)
1861:                        throw new java.util.NoSuchElementException();
1862:                    checkComodification();
1863:
1864:                    _lastRet = _p = _p != null ? _p._prev : _last;
1865:                    _j--;
1866:                    return _lastRet;
1867:                }
1868:
1869:                private void checkComodification() {
1870:                    if (_modCntChd != _modCntSnap)
1871:                        throw new java.util.ConcurrentModificationException();
1872:                }
1873:
1874:                public int nextIndex() {
1875:                    return _j;
1876:                }
1877:
1878:                public int previousIndex() {
1879:                    return _j - 1;
1880:                }
1881:
1882:                public void add(Object o) {
1883:                    final Component newChild = (Component) o;
1884:                    if (newChild.getParent() == AbstractComponent.this )
1885:                        throw new UnsupportedOperationException(
1886:                                "Unable to add component with the same parent: "
1887:                                        + o);
1888:                    //1. it is confusing to allow adding (with replace)
1889:                    //2. the code is sophisticated
1890:                    checkComodification();
1891:
1892:                    insertBefore(newChild, _p);
1893:                    ++_j;
1894:                    _lastRet = null;
1895:                    //spec: cause remove to throw ex if no next/previous
1896:                    ++_modCntSnap;
1897:                    //don't assign _modCntChd directly since deriving class
1898:                    //might manipulate others in insertBefore
1899:                }
1900:
1901:                public void remove() {
1902:                    if (_lastRet == null)
1903:                        throw new IllegalStateException();
1904:                    checkComodification();
1905:
1906:                    removeChild(_lastRet);
1907:
1908:                    if (_p == _lastRet)
1909:                        _p = _lastRet._next; //previous was called
1910:                    else
1911:                        --_j; //next was called
1912:                    _lastRet = null;
1913:                    ++_modCntSnap;
1914:                }
1915:
1916:                public void set(Object o) {
1917:                    throw new UnsupportedOperationException();
1918:                    //Possible to implement this but confusing to developers
1919:                    //if o has the same parent (since we have to move)
1920:                }
1921:            }
1922:
1923:            //Cloneable//
1924:            public Object clone() {
1925:                final AbstractComponent clone;
1926:                try {
1927:                    clone = (AbstractComponent) super .clone();
1928:                } catch (CloneNotSupportedException e) {
1929:                    throw new InternalError();
1930:                }
1931:
1932:                //1. make it not belonging to any page
1933:                clone._page = null;
1934:                clone._parent = null;
1935:
1936:                //1a. clone attributes
1937:                clone._attrs = new HashMap(4);
1938:                for (Iterator it = _attrs.entrySet().iterator(); it.hasNext();) {
1939:                    final Map.Entry me = (Map.Entry) it.next();
1940:                    Object val = me.getValue();
1941:                    if (val instanceof  ComponentCloneListener) {
1942:                        val = ((ComponentCloneListener) val).clone(clone);
1943:                        if (val == null)
1944:                            continue; //don't use it in clone
1945:                    }
1946:                    clone._attrs.put(me.getKey(), val);
1947:                }
1948:
1949:                //1b. clone listeners
1950:                if (_listeners != null) {
1951:                    clone._listeners = new HashMap(4);
1952:                    for (Iterator it = _listeners.entrySet().iterator(); it
1953:                            .hasNext();) {
1954:                        final Map.Entry me = (Map.Entry) it.next();
1955:                        final List list = new LinkedList();
1956:                        for (Iterator it2 = ((List) me.getValue()).iterator(); it2
1957:                                .hasNext();) {
1958:                            Object val = it2.next();
1959:                            if (val instanceof  ComponentCloneListener) {
1960:                                val = ((ComponentCloneListener) val)
1961:                                        .clone(clone);
1962:                                if (val == null)
1963:                                    continue; //don't use it in clone
1964:                            }
1965:                            list.add(val);
1966:                        }
1967:                        if (!list.isEmpty())
1968:                            clone._listeners.put(me.getKey(), list);
1969:                    }
1970:                }
1971:
1972:                if (!_annotsShared && _annots != null)
1973:                    clone._annots = (AnnotationMap) _annots.clone();
1974:                if (!_evthdsShared && _evthds != null)
1975:                    clone._evthds = (EventHandlerMap) _evthds.clone();
1976:
1977:                //2. clone children (deep cloning)
1978:                cloneChildren(clone);
1979:                clone.init(true);
1980:
1981:                //3. spaceinfo
1982:                if (clone._spaceInfo != null) {
1983:                    clone._spaceInfo = new SpaceInfo(clone, _spaceInfo.ns);
1984:                    cloneSpaceInfo(clone, this ._spaceInfo);
1985:                }
1986:
1987:                //4. clone _forwards
1988:                if (clone._forwards != null) {
1989:                    clone._forwards = null;
1990:                    for (Iterator it = _forwards.entrySet().iterator(); it
1991:                            .hasNext();) {
1992:                        final Map.Entry me = (Map.Entry) it.next();
1993:                        final String orgEvent = (String) me.getKey();
1994:
1995:                        final Object[] info = (Object[]) me.getValue();
1996:                        final List fwds = (List) info[1];
1997:                        for (Iterator e = fwds.iterator(); e.hasNext();) {
1998:                            final Object[] fwd = (Object[]) e.next();
1999:                            clone
2000:                                    .addForward0(orgEvent, fwd[0],
2001:                                            (String) fwd[1]);
2002:                        }
2003:                    }
2004:                }
2005:                return clone;
2006:            }
2007:
2008:            private static final void cloneSpaceInfo(AbstractComponent clone,
2009:                    SpaceInfo from) {
2010:                final SpaceInfo to = clone._spaceInfo;
2011:                to.attrs = new HashMap(8);
2012:                for (Iterator it = from.attrs.entrySet().iterator(); it
2013:                        .hasNext();) {
2014:                    final Map.Entry me = (Map.Entry) it.next();
2015:                    Object val = me.getValue();
2016:                    if (val instanceof  ComponentCloneListener) {
2017:                        val = ((ComponentCloneListener) val).clone(clone);
2018:                        if (val == null)
2019:                            continue; //don't use it in clone
2020:                    }
2021:                    to.attrs.put(me.getKey(), val);
2022:                }
2023:
2024:                //rebuild ID space by binding itself and all children
2025:                clone.bindToIdSpace(clone);
2026:                for (AbstractComponent p = clone._first; p != null; p = p._next)
2027:                    addToIdSpacesDown(p, clone);
2028:            }
2029:
2030:            private static final void cloneChildren(final AbstractComponent comp) {
2031:                AbstractComponent q = null;
2032:                for (AbstractComponent p = comp._first; p != null; p = p._next) {
2033:                    AbstractComponent child = (AbstractComponent) p.clone();
2034:                    if (q != null)
2035:                        q._next = child;
2036:                    else
2037:                        comp._first = child;
2038:                    child._prev = q;
2039:                    q = child;
2040:
2041:                    child._parent = comp; //correct it
2042:                    if (child._spaceInfo != null)
2043:                        child._spaceInfo.ns.setParent(comp.getNamespace());
2044:                }
2045:                comp._last = q;
2046:            }
2047:
2048:            //Serializable//
2049:            //NOTE: they must be declared as private
2050:            private synchronized void writeObject(java.io.ObjectOutputStream s)
2051:                    throws java.io.IOException {
2052:                //No need to unshare since they are stored as an independent copy
2053:                //unshareAnnotationMap(false);
2054:                //unshareEventHandlerMap(false);
2055:
2056:                s.defaultWriteObject();
2057:
2058:                //write definition
2059:                if (_def == ComponentsCtrl.DUMMY) {
2060:                    s.writeObject(null);
2061:                } else {
2062:                    LanguageDefinition langdef = _def.getLanguageDefinition();
2063:                    if (langdef != null) {
2064:                        s.writeObject(langdef.getName());
2065:                        s.writeObject(_def.getName());
2066:                    } else {
2067:                        s.writeObject(_def);
2068:                    }
2069:                }
2070:
2071:                //write children
2072:                for (AbstractComponent p = _first; p != null; p = p._next)
2073:                    s.writeObject(p);
2074:                s.writeObject(null);
2075:
2076:                //write attrs
2077:                willSerialize(_attrs.values());
2078:                Serializables.smartWrite(s, _attrs);
2079:
2080:                if (_listeners != null)
2081:                    for (Iterator it = _listeners.entrySet().iterator(); it
2082:                            .hasNext();) {
2083:                        final Map.Entry me = (Map.Entry) it.next();
2084:                        s.writeObject(me.getKey());
2085:
2086:                        final Collection ls = (Collection) me.getValue();
2087:                        willSerialize(ls);
2088:                        Serializables.smartWrite(s, ls);
2089:                    }
2090:                s.writeObject(null);
2091:
2092:                //store _spaceInfo
2093:                if (this  instanceof  IdSpace) {
2094:                    //write _spaceInfo.attrs
2095:                    willSerialize(_spaceInfo.attrs.values());
2096:                    Serializables.smartWrite(s, _spaceInfo.attrs);
2097:
2098:                    //write _spaceInfo.ns (only variables that are not fellows)
2099:                    for (Iterator it = _spaceInfo.ns.getVariableNames()
2100:                            .iterator(); it.hasNext();) {
2101:                        final String nm = (String) it.next();
2102:                        final Object val = _spaceInfo.ns.getVariable(nm, true);
2103:                        willSerialize(val); //always called even if not serializable
2104:
2105:                        if (isVariableSerializable(nm, val)
2106:                                && (val instanceof  java.io.Serializable || val instanceof  java.io.Externalizable)) {
2107:                            s.writeObject(nm);
2108:                            s.writeObject(val);
2109:                        }
2110:                    }
2111:                    s.writeObject(null); //denote end-of-namespace
2112:                }
2113:
2114:                //write _forwards
2115:                if (_forwards != null) {
2116:                    for (Iterator it = _forwards.entrySet().iterator(); it
2117:                            .hasNext();) {
2118:                        final Map.Entry me = (Map.Entry) it.next();
2119:                        s.writeObject(me.getKey()); //original event
2120:
2121:                        final Object[] info = (Object[]) me.getValue();
2122:                        final List fwds = (List) info[1];
2123:                        s.writeInt(fwds.size());
2124:                        for (Iterator e = fwds.iterator(); e.hasNext();) {
2125:                            final Object[] fwd = (Object[]) e.next();
2126:                            s.writeObject( //store target as string
2127:                                    fwd[0] instanceof  Component ? Components
2128:                                            .componentToPath(
2129:                                                    (Component) fwd[0], this )
2130:                                            : fwd[0]);
2131:                            s.writeObject(fwd[1]); //target event
2132:                        }
2133:                    }
2134:                }
2135:                s.writeObject(null);
2136:            }
2137:
2138:            private void willSerialize(Collection c) {
2139:                if (c != null)
2140:                    for (Iterator it = c.iterator(); it.hasNext();)
2141:                        willSerialize(it.next());
2142:            }
2143:
2144:            private void willSerialize(Object o) {
2145:                if (o instanceof  ComponentSerializationListener)
2146:                    ((ComponentSerializationListener) o).willSerialize(this );
2147:            }
2148:
2149:            private synchronized void readObject(java.io.ObjectInputStream s)
2150:                    throws java.io.IOException, ClassNotFoundException {
2151:                s.defaultReadObject();
2152:
2153:                init(false);
2154:
2155:                //read definition
2156:                Object def = s.readObject();
2157:                if (def == null) {
2158:                    _def = ComponentsCtrl.DUMMY;
2159:                } else if (def instanceof  String) {
2160:                    LanguageDefinition langdef = LanguageDefinition
2161:                            .lookup((String) def);
2162:                    _def = langdef.getComponentDefinition((String) s
2163:                            .readObject());
2164:                } else {
2165:                    _def = (ComponentDefinition) def;
2166:                }
2167:
2168:                //read children
2169:                for (AbstractComponent q = null;;) {
2170:                    final AbstractComponent child = (AbstractComponent) s
2171:                            .readObject();
2172:                    if (child == null) {
2173:                        _last = q;
2174:                        break; //no more
2175:                    }
2176:                    if (q != null)
2177:                        q._next = child;
2178:                    else
2179:                        _first = child;
2180:                    child._prev = q;
2181:                    child._parent = this ;
2182:                    q = child;
2183:                }
2184:
2185:                //read attrs
2186:                Serializables.smartRead(s, _attrs);
2187:                didDeserialize(_attrs.values());
2188:
2189:                for (;;) {
2190:                    final String evtnm = (String) s.readObject();
2191:                    if (evtnm == null)
2192:                        break; //no more
2193:
2194:                    if (_listeners == null)
2195:                        _listeners = new HashMap(4);
2196:                    final Collection ls = Serializables.smartRead(s,
2197:                            (Collection) null);
2198:                    _listeners.put(evtnm, ls);
2199:                    didDeserialize(ls);
2200:                }
2201:
2202:                //restore _spaceInfo
2203:                if (this  instanceof  IdSpace) {
2204:                    _spaceInfo = new SpaceInfo(this );
2205:
2206:                    //fix child's _spaceInfo's parent
2207:                    fixSpaceParentOneLevelDown(this , _spaceInfo.ns);
2208:
2209:                    //read _spaceInfo.attrs
2210:                    Serializables.smartRead(s, _spaceInfo.attrs);
2211:                    didDeserialize(_spaceInfo.attrs.values());
2212:
2213:                    //_spaceInfo.ns
2214:                    for (;;) {
2215:                        final String nm = (String) s.readObject();
2216:                        if (nm == null)
2217:                            break; //no more
2218:
2219:                        Object val = s.readObject();
2220:                        _spaceInfo.ns.setVariable(nm, val, true);
2221:                        didDeserialize(val);
2222:                    }
2223:
2224:                    //restore ID space by binding itself and all children
2225:                    bindToIdSpace(this );
2226:                    for (Iterator it = getChildren().iterator(); it.hasNext();)
2227:                        addToIdSpacesDown((Component) it.next(), this );
2228:                }
2229:
2230:                //restore _forwards
2231:                for (;;) {
2232:                    final String orgEvent = (String) s.readObject();
2233:                    if (orgEvent == null)
2234:                        break;
2235:
2236:                    int sz = s.readInt();
2237:                    while (--sz >= 0)
2238:                        addForward0(orgEvent, s.readObject(), (String) s
2239:                                .readObject());
2240:                    //Note: we don't call Components.pathToComponent here
2241:                    //since the parent doesn't deserialized completely
2242:                    //Rather, we handle it until the event is received
2243:                }
2244:            }
2245:
2246:            private void didDeserialize(Collection c) {
2247:                if (c != null)
2248:                    for (Iterator it = c.iterator(); it.hasNext();)
2249:                        didDeserialize(it.next());
2250:            }
2251:
2252:            private void didDeserialize(Object o) {
2253:                if (o instanceof  ComponentSerializationListener)
2254:                    ((ComponentSerializationListener) o).didDeserialize(this );
2255:            }
2256:
2257:            private static boolean isVariableSerializable(String name,
2258:                    Object value) {
2259:                return !"spaceScope".equals(name) && !"spaceOwner".equals(name)
2260:                        && !(value instanceof  Component);
2261:            }
2262:
2263:            /** Fixed Namespace's parent of children only one level.
2264:             */
2265:            private static final void fixSpaceParentOneLevelDown(
2266:                    Component comp, Namespace nsparent) {
2267:                for (Iterator it = comp.getChildren().iterator(); it.hasNext();) {
2268:                    final AbstractComponent child = (AbstractComponent) it
2269:                            .next();
2270:                    //Others are handled by readObject
2271:                    if (child._spaceInfo != null)
2272:                        child._spaceInfo.ns.setParent(nsparent);
2273:                    else
2274:                        fixSpaceParentOneLevelDown(child, nsparent); //recursive
2275:                }
2276:            }
2277:
2278:            /** Used to forward events (for the forward conditions).
2279:             */
2280:            private class ForwardListener implements  EventListener,
2281:                    ComponentCloneListener {
2282:                //Note: it is not serializable since it is handled by
2283:                //AbstractComponent.writeObject
2284:
2285:                private final String _orgEvent;
2286:
2287:                private ForwardListener(String orgEvent) {
2288:                    _orgEvent = orgEvent;
2289:                }
2290:
2291:                public void onEvent(Event event) {
2292:                    final Object[] info = (Object[]) _forwards.get(_orgEvent);
2293:                    if (info != null)
2294:                        for (Iterator it = ((List) info[1]).iterator(); it
2295:                                .hasNext();) {
2296:                            final Object[] fwd = (Object[]) it.next();
2297:                            Component target = fwd[0] instanceof  String ? Components
2298:                                    .pathToComponent((String) fwd[0],
2299:                                            AbstractComponent.this )
2300:                                    : (Component) fwd[0];
2301:
2302:                            if (target == null) {
2303:                                final IdSpace owner = getSpaceOwner();
2304:                                if (owner instanceof  Component) {
2305:                                    target = (Component) owner;
2306:                                } else {
2307:                                    //Use the root component instead
2308:                                    for (target = AbstractComponent.this ;;) {
2309:                                        final Component p = target.getParent();
2310:                                        if (p == null)
2311:                                            break;
2312:                                        target = p;
2313:                                    }
2314:                                }
2315:                            }
2316:
2317:                            Events.postEvent(new ForwardEvent((String) fwd[1],
2318:                                    target, event));
2319:                        }
2320:                }
2321:
2322:                //ComponentCloneListener//
2323:                public Object clone(Component comp) {
2324:                    return null; //handle by AbstractComponent.clone
2325:                }
2326:            }
2327:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.