📄 abstractcomponent.java
字号:
return _adding != null && _adding.contains(child); } /** Sets if the child is being added. */ private void markAdding(Component child, boolean set) { if (set) { if (_adding == null) _adding = new HashSet(2); _adding.add(child); } else { if (_adding != null && _adding.remove(child) && _adding.isEmpty()) _adding = null; } } /** * @param parent the parent (will-be). It may be null. * @param child the child (will-be). It cannot be null. */ private static void checkParentChild(Component parent, Component child) throws UiException { if (parent != null) { if (((AbstractComponent)parent).inAdding(child)) return; //check only once if (Components.isAncestor(child, parent)) throw new UiException("A child cannot be a parent of its ancestor: "+child); if (!parent.isChildable()) throw new UiException(parent+" doesn't allow any child"); final Page parentpg = parent.getPage(), childpg = child.getPage(); if (parentpg != null && childpg != null && parentpg.getDesktop() != childpg.getDesktop()) throw new UiException("The parent and child must be in the same desktop: "+parent); final Component oldparent = child.getParent(); if (parent.getSpaceOwner() != (oldparent != null ? oldparent.getSpaceOwner(): childpg)) checkIdSpacesDown(child, parent); } else { final Page childpg = child.getPage(); if (childpg != null) checkDetach(childpg); } } public boolean insertBefore(Component newChild, Component refChild) { checkParentChild(this, newChild); if (refChild != null && refChild.getParent() != this) refChild = null; final AbstractComponent nc = (AbstractComponent)newChild; final boolean moved = nc._parent == this; //moved in the same parent if (moved) { if (nc._next == refChild) return false; //nothing changed nc.addMoved(this, _page, _page); //detach from original place setNext(nc._prev, nc._next); setPrev(nc._next, nc._prev); } else { //new added //Note: call setParent to detach nc from old parent, if any, //before maintaining nc's _next, _prev... if (!inAdding(nc)) { markAdding(nc, true); try { nc.setParent(this); //spec: callback setParent } finally { markAdding(nc, false); } } else { nc._parent = this; //Set it since deriving class might assume parent is correct //after insertBefore. For example, Tabs.insertBefore(). // //However, we don't call setPage0 and other here, //since the codes will become too complex. //In other words, when super.insertBefore() returns in a //deriving class, _parent is correct but _page may or may not } } if (refChild != null) { final AbstractComponent ref = (AbstractComponent)refChild; setNext(nc, ref); setPrev(nc, ref._prev); setNext(ref._prev, nc); setPrev(ref, nc); } else { if (_last == null) { _first = _last = nc; nc._next = nc._prev = null; } else { _last._next = nc; nc._prev = _last; nc._next = null; _last = nc; } } ++_modCntChd; if (!moved) { //new added ++_nChild; onChildAdded(nc); } return true; } private final void setNext(AbstractComponent comp, AbstractComponent next) { if (comp != null) comp._next = next; else _first = next; } private final void setPrev(AbstractComponent comp, AbstractComponent prev) { if (comp != null) comp._prev = prev; else _last = prev; } /** Appends a child to the end of all children. * It calls {@link #insertBefore} with refChild to be null. * Derives cannot override this method, and they shall override * {@link #insertBefore} instead. */ public final boolean appendChild(Component child) { //Yes, final; see below return insertBefore(child, null); //NOTE: we must go thru insertBefore //such that deriving is easy to override } public boolean removeChild(Component child) { if (child.getParent() != this) return false; //nothing to do final AbstractComponent oc = (AbstractComponent)child; setNext(oc._prev, oc._next); setPrev(oc._next, oc._prev); oc._next = oc._prev = null; if (!inRemoving(oc)) { markRemoving(oc, true); try { oc.setParent(null); //spec: call back setParent } finally { markRemoving(oc, false); } } else { oc._parent = null; //Correct it since deriving class might assume parent is //correct after insertBefore() returns. //refer to insertBefore for more info. } ++_modCntChd; --_nChild; onChildRemoved(child); return true; } /** Default: return true (allows to have children). */ public boolean isChildable() { return true; } public List getChildren() { return _apiChildren; } /** Returns the root of the specified component. */ public Component getRoot() { for (Component comp = this;;) { final Component parent = comp.getParent(); if (parent == null) return comp; comp = parent; } } public boolean isVisible() { return _visible; } public boolean setVisible(boolean visible) { final boolean old = _visible; if (old != visible) { _visible = visible; smartUpdate("visibility", _visible); } return old; } public void invalidate() { if (_page != null) getThisUiEngine().addInvalidate(this); } public void response(String key, AuResponse response) { //if response not depend on this component, it must be generated if (_page != null) { getThisUiEngine().addResponse(key, response); } else if (response.getDepends() != this) { final Execution exec = Executions.getCurrent(); if (exec != null) ((WebAppCtrl)exec.getDesktop().getWebApp()) .getUiEngine().addResponse(key, response); } } public void smartUpdate(String attr, String value) { if (_page != null) getThisUiEngine().addSmartUpdate(this, attr, value); } /** A special smart-update that update a value in int. * <p>It will invoke {@link #smartUpdate(String,String)} to update * the attribute eventually. */ public void smartUpdate(String attr, int value) { smartUpdate(attr, Integer.toString(value)); } /** A special smart-update that update a value in boolean. * <p>It will invoke {@link #smartUpdate(String,String)} to update * the attribute eventually. */ public void smartUpdate(String attr, boolean value) { smartUpdate(attr, Boolean.toString(value)); } public void detach() { if (getParent() != null) setParent(null); else setPage(null); } /** Default: does nothing. * @see Component#onChildAdded */ public void onChildAdded(Component child) { } /** Default: does nothing. * @see Component#onChildRemoved */ public void onChildRemoved(Component child) { } /** Default: handles special event listeners. * @see Component#onPageAttached * @since 3.0.0 */ public void onPageAttached(Page newpage, Page oldpage) { if (oldpage == null) //new added onListenerChanged(newpage.getDesktop(), true); } /** Default: handles special event listeners. * @see Component#onPageDetached * @since 3.0.0 */ public void onPageDetached(Page page) { onListenerChanged(page.getDesktop(), false); } /** Default: null (no propagation at all). */ public Component getPropagatee(String evtnm) { return null; } /** Returns the mold used to render this component. * Default: "default" */ public final String getMold() { return _mold; } public void setMold(String mold) { if (mold == null || mold.length() == 0) mold = "default"; if (!Objects.equals(_mold, mold)) { if (!_def.hasMold(mold)) throw new UiException("Unknown mold: "+mold +", while allowed include "+_def.getMoldNames()); _mold = mold; invalidate(); } } //-- in the redrawing phase --// /** Redraws this component. * This method implements the mold mechanism. * <ol> * <li>It first invokes {@link #getMoldURI} to retrieve the mold * to redraw. The mold is either an URI (String) or a * {@link ComponentRenderer} instance. * <li>If URI, it invokes {@link Execution#include} to generate * the output.</li> * <li>If a {@link ComponentRenderer} instance, {@link ComponentRenderer#render} * is called to generate the output.</li> * </ul> */ public void redraw(Writer out) throws IOException { final Object mold = getMoldURI(); if (mold instanceof ComponentRenderer) { ((ComponentRenderer)mold) .render(this, out != null ? out: ZkFns.getCurrentOut()); } else { final Map attrs = new HashMap(2); attrs.put("self", this); getExecution() .include(out, (String)mold, attrs, Execution.PASS_THRU_ATTR); } } /* Default: does nothing. */ public void onDrawNewChild(Component child, StringBuffer out) throws IOException { } /** Returns whether to send back the request of the specified event * immediately -- i.e., non-deferrable. * Returns true if you want the component (on the server) * to process the event immediately. * * <p>Default: return true if any non-deferable event listener of * the specified event is found. In other words, it returns * {@link Events#isListened} with asap = true. * * <p>This method is moved from {@link HtmlBasedComponent} to * {@link AbstractComponent} since 3.0.0. * * @param evtnm the event name, such as onClick * @since 3.0.0 */ protected boolean isAsapRequired(String evtnm) { return Events.isListened(this, evtnm, true); } /** Appends an attribute for the specified event name, say, onChange, * if a non-deferrable listener is registered. * The format of the generated attribute is as follows: * <code>onChange="true"</code>. * * <p>This method is moved from {@link HtmlBasedComponent} to * {@link AbstractComponent} since 3.0.0. * * @param sb the string buffer to hold the HTML attribute. If null and * {@link #isAsapRequired} is true, a string buffer is created and returned. * @param evtnm the event name, such as onClick * @return the string buffer. If sb is null and {@link #isAsapRequired} * returns false, null is returned. * If the caller passed non-null sb, the returned value must be the same * as sb (so it usually ignores the returned value). * @since 3.0.0 */ protected StringBuffer appendAsapAttr(StringBuffer sb, String evtnm) { if (isAsapRequired(evtnm)) { if (sb == null) sb = new StringBuffer(80); HTMLs.appendAttribute(sb, getAttrOfEvent(evtnm), true); } return sb; } private static String getAttrOfEvent(String evtnm) { return Events.ON_CLICK.equals(evtnm) ? "z.lfclk": Events.ON_RIGHT_CLICK.equals(evtnm) ? "z.rtclk": Events.ON_DOUBLE_CLICK.equals(evtnm) ? "z.dbclk": "z." + evtnm; } public boolean addEventListener(String evtnm, EventListener listener) { if (evtnm == null || listener == null) throw new IllegalArgumentException("null"); if (!Events.isValid(evtnm)) throw new IllegalArgumentException("Invalid event name: "+evtnm); final boolean asap = isAsapRequired(evtnm); if (_listeners == null) _listeners = new HashMap(8); List l = (List)_listeners.get(evtnm); if (l != null) { for (Iterator it = l.iterator(); it.hasNext();) { final EventListener li = (EventListener)it.next(); if (listener.equals(li)) return false; } } else { _listeners.put(evtnm, l = new LinkedList()); } l.add(listener); final Desktop desktop = getDesktop(); if (desktop != null) { if (Events.ON_CLIENT_INFO.equals(evtnm)) response("clientInfo", new AuClientInfo(desktop)); if (Events.ON_PIGGYBACK.equals(evtnm)) ((DesktopCtrl)desktop).onPiggybackListened(this, true); if (!asap && isAsapRequired(evtnm)) smartUpdate(getAttrOfEvent(evtnm), "true"); } return true; } public boolean removeEventListener(String evtnm, EventListener listener) { if (evtnm == null || listener == null) throw new IllegalArgumentException("null"); if (_listeners != null) { final boolean asap = isAsapRequired(evtnm); final List l = (List)_listeners.get(evtnm); if (l != null) { for (Iterator it = l.iterator(); it.hasNext();) { final EventListener li = (EventListener)it.next(); if (listener.equals(li)) { if (l.size() == 1) _listeners.remove(evtnm); else it.remove(); final Desktop desktop = getDesktop(); if (desktop != null) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -