📄 window.java
字号:
/* Window.java{{IS_NOTE Purpose: Description: History: Tue May 31 19:29:13 2005, Created by tomyeh}}IS_NOTECopyright (C) 2005 Potix Corporation. All Rights Reserved.{{IS_RIGHT This program is distributed under GPL Version 2.0 in the hope that it will be useful, but WITHOUT ANY WARRANTY.}}IS_RIGHT*/package org.zkoss.zul;import java.util.Collections;import java.util.Map;import java.util.HashMap;import java.util.Iterator;import java.util.Set;import java.util.LinkedHashSet;import org.zkoss.mesg.MCommon;import org.zkoss.lang.D;import org.zkoss.lang.Objects;import org.zkoss.xml.HTMLs;import org.zkoss.zk.ui.Component;import org.zkoss.zk.ui.Page;import org.zkoss.zk.ui.Executions;import org.zkoss.zk.ui.UiException;import org.zkoss.zk.ui.WrongValueException;import org.zkoss.zk.ui.IdSpace;import org.zkoss.zk.ui.ext.render.MultiBranch;import org.zkoss.zk.ui.event.Events;import org.zkoss.zk.au.*;import org.zkoss.zul.impl.XulElement;import org.zkoss.zul.au.*;/** * A generic window. * * <p>Unlike other elements, each {@link Window} is an independent ID space * (by implementing {@link IdSpace}). * It means a window and all its descendants forms a ID space and * the ID of each of them is unique in this space. * You could retrieve any of them in this space by calling {@link #getFellow}. * * <p>If a window X is a descendant of another window Y, X's descendants * are not visible in Y's space. To retrieve a descendant, say Z, of X, * you have to invoke Y.getFellow('X').getFellow('Z'). * * <p>Events:<br> * onMove, onShow, onOK, onCacnel and onCtrlKey. * * @author tomyeh */public class Window extends XulElement implements IdSpace { private transient Caption _caption; private String _border = "none"; private String _title = ""; /** What control and function keys to intercepts. */ private String _ctrlKeys; /** The value passed to the client; parsed from _ctrlKeys. */ private String _ctkeys; /** One of MODAL, EMBEDDED, OVERLAPPED. */ private int _mode = EMBEDDED; /** Used for doModal. */ private transient Object _mutex; /** Whether this window is in a special mode that need to be ended. */ private boolean _moding; /** Whether to show a close button. */ private boolean _closable; /** Whether the window is sizable. */ private boolean _sizable; /** Embeds the window as normal component. */ private static final int EMBEDDED = 0; /** Makes the window as a modal dialog. */ private static final int MODAL = 1; /** Makes the window as overlap other components. */ private static final int OVERLAPPED = 2; /** Makes the window as popup. * It is similar to {@link #OVERLAPPED}, except it is auto hidden * when user clicks outside of the window. */ private static final int POPUP = 3; public Window() { init(); } /** * @param title the window title (see {@link #setTitle}). * @param border the border (see {@link #setBorder}). * @param closable whether it is closable (see {@link #setClosable}). */ public Window(String title, String border, boolean closable) { this(); setTitle(title); setBorder(border); setClosable(closable); } private void init() { _mutex = new Object(); } /** Returns the caption of this window. */ public Caption getCaption() { return _caption; } /** Returns the border. * <p>The border actually controls what CSS class to use: * If border is null, it implies "none". * If border is "normal", the class called "window" is used. * If not, the class called "window-<i>border</i>" (e.g., "window-none"). * * <p>If you also specify the CSS class ({@link #setClass}), it * overwrites whatever border you specify here. * * <p>Default: "none". */ public String getBorder() { return _border; } /** Sets the border (either none or normal). */ public void setBorder(String border) { if (border == null) border = "none"; if (!Objects.equals(_border, border)) { _border = border; smartUpdate("class", getSclass()); } } /** Returns the title. * Besides this attribute, you could use {@link Caption} to define * a more sophiscated caption (aka., title). * <p>If a window has a caption whose label ({@link Caption#getLabel}) * is not empty, then this attribute is ignored. * <p>Default: empty. */ public String getTitle() { return _title; } /** Sets the title. */ public void setTitle(String title) { if (title == null) title = ""; if (!Objects.equals(_title, title)) { _title = title; if (_caption != null) _caption.invalidate(); else invalidate(); } } /** Returns what keystrokes to intercept. * <p>Default: null. */ public String getCtrlKeys() { return _ctrlKeys; } /** Sets what keystrokes to intercept. * * <p>The string could be a combination of the following: * <dl> * <dt>^k</dt> * <dd>A control key, i.e., Ctrl+k, where k could be a~z, 0~9, #n</dd> * <dt>@k</dt> * <dd>A alt key, i.e., Alt+k, where k could be a~z, 0~9, #n</dd> * <dt>$k</dt> * <dd>A shift key, i.e., Shift+k, where k could be #n</dd> * <dt>#home</dt> * <dd>Home</dd> * <dt>#end</dt> * <dd>End</dd> * <dt>#ins</dt> * <dd>Insert</dd> * <dt>#del</dt> * <dd>Delete</dd> * <dt>#left</dt> * <dd>Left arrow</dd> * <dt>#right</dt> * <dd>Right arrow</dd> * <dt>#up</dt> * <dd>Up arrow</dd> * <dt>#down</dt> * <dd>Down arrow</dd> * <dt>#pgup</dt> * <dd>PageUp</dd> * <dt>#pgdn</dt> * <dd>PageDn</dd> * <dt>#f1 #f2 ... #f12</dt> * <dd>Function keys representing F1, F2, ... F12</dd> * </dl> * * <p>For example, * <dl> * <dt>^a^d@c#f10#left#right</dt> * <dd>It means you want to intercept Ctrl+A, Ctrl+D, Alt+C, F10, * Left and Right.</dd> * <dt>^#left</dt> * <dd>It means Ctrl+Left.</dd> * <dt>^#f1</dt> * <dd>It means Ctrl+F1.</dd> * <dt>@#f3</dt> * <dd>It means Alt+F3.</dd> * </dl> * * <p>Note: it doesn't support Ctrl+Alt, Shift+Ctrl, Shift+Alt or Shift+Ctrl+Alt. */ public void setCtrlKeys(String ctrlKeys) throws UiException { if (ctrlKeys != null && ctrlKeys.length() == 0) ctrlKeys = null; if (!Objects.equals(_ctrlKeys, ctrlKeys)) { parseCtrlKeys(ctrlKeys); smartUpdate("z.ctkeys", _ctkeys); } } private void parseCtrlKeys(String keys) throws UiException { if (keys == null || keys.length() == 0) { _ctrlKeys = _ctkeys = null; return; } final StringBuffer sbctl = new StringBuffer(), sbsft = new StringBuffer(), sbalt = new StringBuffer(), sbext = new StringBuffer(); StringBuffer sbcur = null; for (int j = 0, len = keys.length(); j < len; ++j) { char cc = keys.charAt(j); switch (cc) { case '^': case '$': case '@': if (sbcur != null) throw new WrongValueException("Combination of Shift, Alt and Ctrl not supported: "+keys); sbcur = cc == '^' ? sbctl: cc == '@' ? sbalt: sbsft; break; case '#': { int k = j + 1; for (; k < len; ++k) { final char c2 = (char)keys.charAt(k); if ((c2 > 'Z' || c2 < 'A') && (c2 > 'z' || c2 < 'a') && (c2 > '9' || c2 < '0')) break; } if (k == j + 1) throw new WrongValueException(MCommon.UNEXPECTED_CHARACTER, new Object[] {new Character(cc), keys}); final String s = keys.substring(j+1, k).toLowerCase(); if ("pgup".equals(s)) cc = 'A'; else if ("pgdn".equals(s)) cc = 'B'; else if ("end".equals(s)) cc = 'C'; else if ("home".equals(s)) cc = 'D'; else if ("left".equals(s)) cc = 'E'; else if ("up".equals(s)) cc = 'F'; else if ("right".equals(s)) cc = 'G'; else if ("down".equals(s)) cc = 'H'; else if ("ins".equals(s)) cc = 'I'; else if ("del".equals(s)) cc = 'J'; else if (s.length() > 1 && s.charAt(0) == 'f') { final int v; try { v = Integer.parseInt(s.substring(1)); } catch (Throwable ex) { throw new WrongValueException("Unknown #"+s+" in "+keys); } if (v == 0 || v > 12) throw new WrongValueException("Unsupported function key: #f"+v); cc = (char)('O' + v); //'P': F1, 'Q': F2... 'Z': F12 } else throw new WrongValueException("Unknown #"+s+" in "+keys); if (sbcur == null) sbext.append(cc); else { sbcur.append(cc); sbcur = null; } j = k - 1; } break; default: if (sbcur == null || ((cc > 'Z' || cc < 'A') && (cc > 'z' || cc < 'a') && (cc > '9' || cc < '0'))) throw new WrongValueException(MCommon.UNEXPECTED_CHARACTER, new Object[] {new Character(cc), keys}); if (sbcur == sbsft) throw new WrongValueException("$"+cc+" not supported: "+keys); if (cc <= 'Z' && cc >= 'A') cc = (char)(cc + ('a' - 'A')); //to lower case sbcur.append(cc); sbcur = null; break; } } _ctkeys = new StringBuffer() .append('^').append(sbctl).append(';') .append('@').append(sbalt).append(';') .append('$').append(sbsft).append(';') .append('#').append(sbext).append(';').toString(); _ctrlKeys = keys; } /** Returns the current mode. * One of "modal", "embedded", "overlapped" and "popup". */ public String getMode() { switch (_mode) { case MODAL: return "modal"; case POPUP: return "popup"; case OVERLAPPED: return "overlapped"; default: return "embedded"; } } /** Sets the mode. * * <p>Notice that you can specify "modal" to this method only in an event * listener ({@link Events#inEventListener}). * Rather, you shall use {@link org.zkoss.zk.ui.event.Events#postEvent} to * post the onModal event. For example, in a ZUML page, you can put a window * into modal immediately after rendered as follows. * * <pre><code> *<window title="..."> *... * <zscript> * Events.postEvent(Events.ON_MODAL, self, null); * </zscript> *</window> * * @param name the mode which could be one of * "embedded", "overlapped" and "popup".
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -