📄 uivisualizer.java
字号:
} return false; } /** Returns a list of {@link AuResponse} according to what components * are invalidated and attached. */ public List getResponses() throws IOException {/* if (D.ON && log.finerable()) log.finer("ei: "+this+"\nInvalidated: "+_invalidated+"\nSmart Upd: "+_smartUpdated +"\nAttached: "+_attached+"\nMoved:"+_moved+"\nResponses:"+_responses +"\npgInvalid: "+_pgInvalid +"\nUuidChanged: "+_idChgd);*/ final List responses = new LinkedList(); //1. process dead comonents, cropping and the removed page { //1a. handle _moved //The reason to remove first: some insertion might fail if the old //componetns are not removed yet //Also, we have to remove both parent and child because, at //the client, they might not be parent-child relationship Set removed = doMoved(responses); //after called, _moved is cleared (add to _attached if necessary) //1b. remove reduntant removeRedundant(_invalidated); removeRedundant(_attached); removeCrossRedundant(); //1c. process Cropper if (doCrop()) { //optimize it again since new invalidated is added removeRedundant(_invalidated); removeCrossRedundant(); } //1d. prepare removed pages and optimize for invalidate or removed pages checkPageRemoved(removed); //maintain _pgRemoved for pages being removed } //2. Process removed and invalid pages //2a. clean up _invalidated and others belonging to invalid pages if (_pgInvalid != null && _pgInvalid.isEmpty()) _pgInvalid = null; if (_pgRemoved != null && _pgRemoved.isEmpty()) _pgRemoved = null; if (_pgInvalid != null || _pgRemoved != null) { clearInInvalidPage(_invalidated); clearInInvalidPage(_attached); clearInInvalidPage(_smartUpdated.keySet()); if (_idChgd != null) clearInInvalidPage(_idChgd.keySet()); } //2b. remove pages. Note: we don't need to generate rm, becausee they //are included pages. if (_pgRemoved != null) { final DesktopCtrl dtctl = (DesktopCtrl)_exec.getDesktop(); for (final Iterator it = _pgRemoved.iterator(); it.hasNext();) dtctl.removePage((Page)it.next()); } //2c. generate response for invalidated pages if (_pgInvalid != null) { for (final Iterator it = _pgInvalid.iterator(); it.hasNext();) { final Page page = (Page)it.next(); responses.add(new AuReplace(page, redraw(page))); } } //3. Remove components who is moved and its UUID is changed if (_idChgd != null) { for (Iterator it = _idChgd.values().iterator(); it.hasNext();) responses.add(new AuRemove((String)it.next())); _idChgd = null; //just in case }/* if (log.finerable()) log.finer("After removing redudant: invalidated: "+_invalidated +"\nAttached: "+_attached+"\nSmartUpd:"+_smartUpdated);*/ //4. process special interfaces doChildChanged(); //ChildChangedAware //5. generate replace for invalidated for (Iterator it = _invalidated.iterator(); it.hasNext();) { final Component comp = (Component)it.next(); responses.add(new AuReplace(comp, redraw(comp))); } _ending = true; //no more addSmartUpdate... //6. add attached components (including setParent) //Due to cyclic references, we have to process all siblings //at the same time final List desktops = new LinkedList(); final Component[] attached = (Component[]) _attached.toArray(new Component[_attached.size()]); for (int j = 0; j < attached.length; ++j) { final Component comp = attached[j]; //Note: attached comp might change from another page to //the one being created. In this case, no need to add if (comp != null) { final Page page = comp.getPage(); if (page != null && _exec.isAsyncUpdate(page)) { final Component parent = comp.getParent(); final Set newsibs = new LinkedHashSet(37); newsibs.add(comp); desktops.add(newsibs); for (int k = j + 1; k < attached.length; ++k) { final Component ck = attached[k]; if (ck != null && ck.getParent() == parent) { newsibs.add(ck); attached[k] = null; } } } } } for (Iterator it = desktops.iterator(); it.hasNext();) { final Set newsibs = (Set)it.next(); addResponsesForCreatedPerSiblings(responses, newsibs); } //7. Adds smart updates and response at once based on their time stamp final List tvals = new LinkedList(); for (Iterator it = _smartUpdated.values().iterator(); it.hasNext();) { final Map attrs = (Map)it.next(); tvals.addAll(attrs.values()); } if (_responses != null) { for (Iterator it = _responses.values().iterator(); it.hasNext();) { final Map resps = (Map)it.next(); final List keyless = (List)resps.remove(null); //key == null if (keyless != null) tvals.addAll(keyless); tvals.addAll(resps.values()); //key != null } } if (!tvals.isEmpty()) { final TimedValue[] tvs = (TimedValue[])tvals.toArray(new TimedValue[tvals.size()]); Arrays.sort(tvs); for (int j = 0; j < tvs.length; ++j) responses.add(tvs[j].getResponse()); } //any aborting reason //Note: we don't give up other responses (Bug 1647085) if (_aborting != null) { final AuResponse abtresp = _aborting.getResponse(); if (abtresp != null) responses.add(abtresp); //add to the end } //free memory _invalidated.clear(); _smartUpdated.clear(); _attached.clear(); _pgInvalid = _pgRemoved = null; _responses = null;// if (D.ON && log.debugable()) log.debug("Return responses: "+responses);// System.out.println("Return responses: "+responses); return responses; } /** process moved components. * * <p>After called, _moved becomes empty. * If they are removed, correponding AuRemove are generated. * If not, they are added to _attached. * * @return the dead components (i.e., not belong to any page) */ private Set doMoved(List responses) { //Remove components that have to removed from the client final Set removed = new HashSet(); for (Iterator it = _moved.iterator(); it.hasNext();) { final Component comp = (Component)it.next(); final Page page = comp.getPage(); if (page == null) { removed.add(comp); if (_responses != null) _responses.remove(comp); _invalidated.remove(comp); _smartUpdated.remove(comp); responses.add(new AuRemove(comp)); } else { //page != null if (_exec.isAsyncUpdate(page)) responses.add(new AuRemove(comp)); _attached.add(comp); //copy to _attached since we handle them later in the same way } } _moved.clear(); //no longer required return removed; } /** Adds responses for a set of siblings which is new attached (or * parent is changed). */ private static void addResponsesForCreatedPerSiblings(List responses, Set newsibs) throws IOException { final Component parent; final Page page; { final Component comp = (Component)newsibs.iterator().next(); parent = comp.getParent(); page = comp.getPage(); } final Collection sibs; if (parent != null) { sibs = parent.getChildren(); } else { sibs = page.getRoots(); }// if (D.ON && log.finerable()) log.finer("All sibs: "+sibs+" newsibs: "+newsibs); /* Algorithm: 1. Locate a sibling, say <a>, that already exists. 2. Then, use AuInsertBefore for all sibling before <a>, and AuInsertAfter for all after anchor. 3. If anchor is not found, use AuAppendChild for the first and INSERT_AFTER for the rest */ final List before = new LinkedList(); Component anchor = null; final ComponentCtrl parentCtrl = (ComponentCtrl)parent; final Object parentxc = parentCtrl != null ? parentCtrl.getExtraCtrl(): null; for (Iterator it = sibs.iterator(); it.hasNext();) { final Component comp = (Component)it.next(); if ((parentxc instanceof MultiBranch) && ((MultiBranch)parentxc).inDifferentBranch(comp)) continue; if (anchor != null) { if (newsibs.remove(comp)) { responses.add(new AuInsertAfter(anchor, drawNew(comp))); if (newsibs.isEmpty()) return; //done (all newsibs are processed) anchor = comp; } else { anchor = comp; } } else if (newsibs.remove(comp)) { before.add(comp); } else { //Generate before in the reverse order and INSERT_BEFORE anchor = comp; for (ListIterator i2 = before.listIterator(before.size()); i2.hasPrevious();) { final Component c = (Component)i2.previous(); responses.add(new AuInsertBefore(anchor, drawNew(c))); anchor = c; } if (newsibs.isEmpty()) return; //done (all newsibs are processed) anchor = comp; } } assert D.OFF || (anchor == null && newsibs.isEmpty()): "anchor="+anchor+" newsibs="+newsibs+" sibs="+sibs; //all siblings are changed (and none of them is processed) final Iterator it = before.iterator(); anchor = (Component)it.next(); responses.add( parent != null ? new AuAppendChild(parent, drawNew(anchor)): new AuAppendChild(page, drawNew(anchor))); while (it.hasNext()) { final Component comp = (Component)it.next(); responses.add(new AuInsertAfter(anchor, drawNew(comp))); anchor = comp; } } /** Removes redundant components (i.e., an descendant of another). */ private static void removeRedundant(Set comps) { rudLoop: for (Iterator j = comps.iterator(); j.hasNext();) { final Component cj = (Component)j.next(); for (Iterator k = comps.iterator(); k.hasNext();) { final Component ck = (Component)k.next(); if (ck != cj && Components.isAncestor(ck, cj)) { j.remove(); continue rudLoop; } } } } /** Removes redundant components cross _invalidate, _smartUpdate * and _attached. */ private void removeCrossRedundant() { invLoop: for (Iterator j = _invalidated.iterator(); j.hasNext();) { final Component cj = (Component)j.next(); for (Iterator k = _attached.iterator(); k.hasNext();) { final Component ck = (Component)k.next(); if (Components.isAncestor(ck, cj)) { //includes ck == cj j.remove(); continue invLoop; } else if (Components.isAncestor(cj, ck)) { k.remove(); } } } suLoop: for (Iterator j = _smartUpdated.keySet().iterator(); j.hasNext();) { final Component cj = (Component)j.next(); for (Iterator k = _invalidated.iterator(); k.hasNext();) { final Component ck = (Component)k.next(); if (Components.isAncestor(ck, cj)) { j.remove(); continue suLoop; } } for (Iterator k = _attached.iterator(); k.hasNext();) { final Component ck = (Component)k.next(); if (Components.isAncestor(ck, cj)) { j.remove(); continue suLoop; } } } } /** Draws a new attached component into a string. */ private static String drawNew(Component comp) throws IOException { final StringWriter out = new StringWriter(1024*8); comp.redraw(out); final StringBuffer buf = out.getBuffer(); final Component parent = comp.getParent(); if (parent != null) parent.onDrawNewChild(comp, buf); return buf.toString(); } /** Redraw the specified component into a string. */ private static String redraw(Component comp) throws IOException { final StringWriter out = new StringWriter(1024*8); comp.redraw(out); return out.toString(); } /** Redraws the whole page. */ private static String redraw(Page page) throws IOException { final StringWriter out = new StringWriter(1024*8); ((PageCtrl)page).redraw(null, out); return out.toString(); } /** Called before a component redraws itself if the component might * include another page. */ public void pushOwner(Component comp) { _1stec._owners.add(0, comp); } /** Called after a component redraws itself if it ever calls * {@link #pushOwner}. */ public void popOwner() { _1stec._owners.remove(0); } /** Returns the owner component for this execution, or null if * this execution is not owned by any component. * The owner is the top of the stack pushed by {@link #pushOwner}. */ public Component getOwner() { return _1stec._owners.isEmpty() ? null: (Component)_1stec._owners.get(0); } /** Used to hold smart update and response with a time stamp. */ private static class TimedValue implements Comparable { private final int _timed; private final AuResponse _response; private TimedValue(int timed, AuResponse response) { _timed = timed; _response = response; } private TimedValue(int timed, Component comp, String name, String value) { _timed = timed; if (value != null) _response = new AuSetAttribute(comp, name, value); else _response = new AuRemoveAttribute(comp, name); } public String toString() { return '(' + _timed + ":" + _response + ')'; } public int compareTo(Object o) { final int t = ((TimedValue)o)._timed; return _timed > t ? 1: _timed == t ? 0: -1; } /** Returns the response representing this object. */ private AuResponse getResponse() { return _response; } }; /** Sets the reason to abort the current execution. * if not null, it means the current execution is aborting * and the specified argument is the reason to aborting. * Its interpretation depends on {@link org.zkoss.zk.ui.sys.UiEngine}. * * <p>Note: if setAbortingReason is ever set with non-null, you * CANNOT set it back to null. * * <p>The aborting flag means no more processing, i.e., dropping pending * requests, events, and rendering. * * <p>After call this method, you shall not keep processing the page * because the rendering is dropped and the client is out-of-sync * with the server. * * <p>This method doesn't really abort pending events and requests. * It just set a flag, {@link #getAbortingReason}, and it is * {@link org.zkoss.zk.ui.sys.UiEngine}'s job to detect this flag * and handling it properly. */ public void setAbortingReason(AbortingReason reason) { if (_aborting != null && reason == null) throw new IllegalStateException("Aborting reason is set and you cannot clear it"); //Reason: some event or request might be skipped //so clearing it might cause unexpected results _aborting = reason; } /** Returns the reason to aborting, or null if no aborting at all. * * @see #setAbortingReason */ public AbortingReason getAbortingReason() { return _aborting; } /** Returns whether it is aborting. * * <p>The execution is aborting if {@link #getAbortingReason} returns * not null and the returned reason's {@link AbortingReason#isAborting} * is true. * * <p>Note: {@link Execution#isVoid} means the execution is voided * and no output shall be generated. The request is taken charged * by other servlet. * On the other hand, {@link #isAborting} means the execution * is aborting and the output shall still be generated (and sent). * The request is still taken charged by this execution. */ public boolean isAborting() { return _aborting != null && _aborting.isAborting(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -