001: /* Bandbox.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Mon Mar 20 12:14:46 2006, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2006 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: }}IS_RIGHT
016: */
017: package org.zkoss.zul;
018:
019: import org.zkoss.lang.Objects;
020: import org.zkoss.xml.HTMLs;
021:
022: import org.zkoss.zk.ui.Component;
023: import org.zkoss.zk.ui.UiException;
024: import org.zkoss.zk.ui.WrongValueException;
025: import org.zkoss.zk.ui.event.Events;
026: import org.zkoss.zk.au.out.AuInvoke;
027:
028: /**
029: * A band box. A bank box consists of an input box ({@link Textbox} and
030: * a popup window {@link Bandpopup}.
031: * It is similar to {@link Combobox} except the popup window could have
032: * any kind of children. For example, you could place a textbox in
033: * the popup to let user search particular items.
034: *
035: * <p>Default {@link #getSclass}: bandbox.
036: *
037: * <p>Events: onOpen<br/>
038: * Developers can listen to the onOpen event and initializes it
039: * when {@link org.zkoss.zk.ui.event.OpenEvent#isOpen} is true, and/or
040: * clean up if false.
041: *
042: * <p>Note: to have better performance, onOpen is sent only if
043: * a non-deferrable event listener is registered
044: * (see {@link org.zkoss.zk.ui.event.Deferrable}).
045: *
046: * @author tomyeh
047: */
048: public class Bandbox extends Textbox {
049: private static final String DEFAULT_IMAGE = "~./zul/img/bandbtn.gif";
050: private transient Bandpopup _drop;
051: private String _img;
052: private boolean _autodrop, _btnVisible = true;
053:
054: public Bandbox() {
055: setSclass("bandbox");
056: }
057:
058: public Bandbox(String value) throws WrongValueException {
059: this ();
060: setValue(value);
061: }
062:
063: /** Returns the dropdown window belonging to this band box.
064: */
065: public Bandpopup getDropdown() {
066: return _drop;
067: }
068:
069: /** Closes the popup ({@link #getDropdown}).
070: */
071: public void closeDropdown() {
072: response("close", new AuInvoke(this , "cbclose"));
073: }
074:
075: /** Returns whether to automatically drop the list if users is changing
076: * this text box.
077: * <p>Default: false.
078: */
079: public boolean isAutodrop() {
080: return _autodrop;
081: }
082:
083: /** Sets whether to automatically drop the list if users is changing
084: * this text box.
085: */
086: public void setAutodrop(boolean autodrop) {
087: if (_autodrop != autodrop) {
088: _autodrop = autodrop;
089: smartUpdate("z.adr", autodrop);
090: }
091: }
092:
093: /** Returns whether the button (on the right of the textbox) is visible.
094: * <p>Default: true.
095: */
096: public boolean isButtonVisible() {
097: return _btnVisible;
098: }
099:
100: /** Sets whether the button (on the right of the textbox) is visible.
101: */
102: public void setButtonVisible(boolean visible) {
103: if (_btnVisible != visible) {
104: _btnVisible = visible;
105: smartUpdate("z.btnVisi", visible);
106: }
107: }
108:
109: /** Returns the image URI that is displayed as the button to open
110: * {@link Bandpopup}.
111: * <p>Default: "~./zul/img/bandbtn.gif".
112: */
113: public String getImage() {
114: return _img != null ? _img : DEFAULT_IMAGE;
115: }
116:
117: /** Sets the image URI that is displayed as the button to open
118: * {@link Bandpopup}.
119: *
120: * @param img the image URI. If null or empty, it is reset to
121: * the default value: "~./zul/img/bandbtn.gif".
122: */
123: public void setImage(String img) {
124: if (img != null
125: && (img.length() == 0 || DEFAULT_IMAGE.equals(img)))
126: img = null;
127: if (!Objects.equals(_img, img)) {
128: _img = img;
129: invalidate();
130: //NOTE: Tom Yeh: 20051222
131: //It is possible to use smartUpdate if we always generate
132: //an image (with an ID) in getImgTag.
133: //However, it is too costly by making HTML too big, so
134: //we prefer to invalidate (it happens rarely)
135: }
136: }
137:
138: /** Drops down or closes the child.
139: *
140: * @since 3.0.1
141: * @see #open
142: * @see #close
143: */
144: public void setOpen(boolean open) {
145: if (open)
146: open();
147: else
148: close();
149: }
150:
151: /** Drops down the child.
152: * The same as setOpen(true).
153: *
154: * @since 3.0.1
155: */
156: public void open() {
157: response("dropdn", new AuInvoke(this , "dropdn", true));
158: }
159:
160: /** Closes the child if it was dropped down.
161: * The same as setOpen(false).
162: *
163: * @since 3.0.1
164: */
165: public void close() {
166: response("dropdn", new AuInvoke(this , "dropdn", false));
167: }
168:
169: //-- super --//
170: public void setMultiline(boolean multiline) {
171: if (multiline)
172: throw new UnsupportedOperationException(
173: "Bandbox doesn't support multiline");
174: }
175:
176: public void setRows(int rows) {
177: if (rows != 1)
178: throw new UnsupportedOperationException(
179: "Bandbox doesn't support multiple rows, " + rows);
180: }
181:
182: public String getOuterAttrs() {
183: final String attrs = super .getOuterAttrs();
184: final boolean adr = isAutodrop();
185: if (!isAsapRequired(Events.ON_OPEN) && !adr)
186: return attrs;
187:
188: final StringBuffer sb = new StringBuffer(64).append(attrs);
189: appendAsapAttr(sb, Events.ON_OPEN);
190: if (adr)
191: HTMLs.appendAttribute(sb, "z.adr", "true");
192: return sb.toString();
193: }
194:
195: public String getInnerAttrs() {
196: final String attrs = super .getInnerAttrs();
197: final String style = getInnerStyle();
198: return style.length() > 0 ? attrs + " style=\"" + style + '"'
199: : attrs;
200: }
201:
202: private String getInnerStyle() {
203: final StringBuffer sb = new StringBuffer(32).append(HTMLs
204: .getTextRelevantStyle(getRealStyle()));
205: HTMLs.appendStyle(sb, "width", getWidth());
206: HTMLs.appendStyle(sb, "height", getHeight());
207: return sb.toString();
208: }
209:
210: /** Returns RS_NO_WIDTH|RS_NO_HEIGHT.
211: */
212: protected int getRealStyleFlags() {
213: return super .getRealStyleFlags() | RS_NO_WIDTH | RS_NO_HEIGHT;
214: }
215:
216: //-- Component --//
217: public boolean insertBefore(Component newChild, Component refChild) {
218: if (!(newChild instanceof Bandpopup))
219: throw new UiException("Unsupported child for Bandbox: "
220: + newChild);
221: if (_drop != null)
222: throw new UiException("At most one bandpopup is allowed, "
223: + this );
224: if (super .insertBefore(newChild, refChild)) {
225: invalidate();
226: _drop = (Bandpopup) newChild;
227: return true;
228: }
229: return false;
230: }
231:
232: /** Childable. */
233: public boolean isChildable() {
234: return true;
235: }
236:
237: public void onChildRemoved(Component child) {
238: super .onChildRemoved(child);
239: if (child == _drop)
240: _drop = null; //just in case
241: }
242:
243: //Cloneable//
244: public Object clone() {
245: final Bandbox clone = (Bandbox) super .clone();
246: if (clone._drop != null)
247: clone.afterUnmarshal();
248: return clone;
249: }
250:
251: private void afterUnmarshal() {
252: _drop = (Bandpopup) getFirstChild();
253: }
254:
255: //Serializable//
256: private synchronized void readObject(java.io.ObjectInputStream s)
257: throws java.io.IOException, ClassNotFoundException {
258: s.defaultReadObject();
259:
260: if (!getChildren().isEmpty())
261: afterUnmarshal();
262: }
263: }
|