0001: /*
0002: * MyGWT Widget Library
0003: * Copyright(c) 2007, MyGWT.
0004: * licensing@mygwt.net
0005: *
0006: * http://mygwt.net/license
0007: */
0008: package net.mygwt.ui.client.widget;
0009:
0010: import java.util.EventListener;
0011: import java.util.HashMap;
0012:
0013: import net.mygwt.ui.client.Events;
0014: import net.mygwt.ui.client.MyDOM;
0015: import net.mygwt.ui.client.MyGWT;
0016: import net.mygwt.ui.client.Style;
0017: import net.mygwt.ui.client.event.BaseEvent;
0018: import net.mygwt.ui.client.event.Listener;
0019: import net.mygwt.ui.client.event.TypedListener;
0020: import net.mygwt.ui.client.event.WidgetListener;
0021: import net.mygwt.ui.client.util.Observable;
0022: import net.mygwt.ui.client.util.Rectangle;
0023: import net.mygwt.ui.client.widget.menu.Menu;
0024:
0025: import com.google.gwt.user.client.Command;
0026: import com.google.gwt.user.client.DOM;
0027: import com.google.gwt.user.client.DeferredCommand;
0028: import com.google.gwt.user.client.Element;
0029: import com.google.gwt.user.client.Event;
0030: import com.google.gwt.user.client.ui.HasWidgets;
0031: import com.google.gwt.user.client.ui.Widget;
0032:
0033: /**
0034: * Base class for MyGWT widgets.
0035: *
0036: * <dl>
0037: * <dt>Events:</dt>
0038: *
0039: * <dd><b>Resize</b> : (widget, width, height)<br>
0040: * <div>Fires when the components location or size change.</div>
0041: * <ul>
0042: * <li>widget : this</li>
0043: * <li>width : the widget width</li>
0044: * <li>height : the widget height</li>
0045: * </ul>
0046: * </dd>
0047: *
0048: * <dd><b>Enable</b> : (widget)<br>
0049: * <div>Fires after the component is enabled.</div>
0050: * <ul>
0051: * <li>widget : this</li>
0052: * </ul>
0053: * </dd>
0054: *
0055: * <dd><b>Disable</b> : (widget)<br>
0056: * <div>Fires after the component is disabled.</div>
0057: * <ul>
0058: * <li>widget : this</li>
0059: * </ul>
0060: * </dd>
0061: *
0062: * <dd><b>BeforeDispose</b> : (widget)<br>
0063: * <div>Fires before the component is disposed.</div>
0064: * <ul>
0065: * <li>widget : this</li>
0066: * </ul>
0067: * </dd>
0068: *
0069: * <dd><b>Dispose</b> : (widget)<br>
0070: * <div>Fires after the component is disposed.</div>
0071: * <ul>
0072: * <li>widget : this</li>
0073: * </ul>
0074: * </dd>
0075: *
0076: * <dd><b>BeforeHide</b> : (widget)<br>
0077: * <div>Fires before the component is hidden.</div>
0078: * <ul>
0079: * <li>widget : this</li>
0080: * </ul>
0081: * </dd>
0082: *
0083: * <dd><b>BeforeShow</b> : (widget)<br>
0084: * <div>Fires before the component is shown.</div>
0085: * <ul>
0086: * <li>widget : this</li>
0087: * </ul>
0088: * </dd>
0089: *
0090: * <dd><b>Hide</b> : (widget)<br>
0091: * <div>Fires after the component is hidden.</div>
0092: * <ul>
0093: * <li>widget : this</li>
0094: * </ul>
0095: * </dd>
0096: *
0097: * <dd><b>Show</b> : (widget)<br>
0098: * <div>Fires after the component is shown.</div>
0099: * <ul>
0100: * <li>widget : this</li>
0101: * </ul>
0102: * </dd>
0103: *
0104: * <dd><b>ContextMenu</b> : (widget)<br>
0105: * <div>Fires before the components context menu is shown. Listeners can set the
0106: * <code>doit</code> field to <code>false</code> to cancel the action.</div>
0107: * <ul>
0108: * <li>widget : this</li>
0109: * </ul>
0110: * </dd>
0111: *
0112: * <dd><b>Attach</b> : (widget)<br>
0113: * <div>Fires after the component is attached.</div>
0114: * <ul>
0115: * <li>widget : this</li>
0116: * </ul>
0117: * </dd>
0118: *
0119: * <dd><b>Detach</b> : (widget) <br>
0120: * <div>Fires after the component is detached.</div>
0121: * <ul>
0122: * <li>widget : this</li>
0123: * </ul>
0124: * </dd>
0125: *
0126: * <dd><b>Render</b> : (widget)<br>
0127: * <div>Fires after the component is rendered.</div>
0128: * <ul>
0129: * <li>widget : this</li>
0130: * </ul>
0131: * </dd>
0132: *
0133: * </dl>
0134: */
0135: public abstract class Component extends Widget {
0136:
0137: // hack to ensure MyGWT is initialized
0138: static {
0139: MyGWT.init();
0140: }
0141:
0142: /**
0143: * The base style is typically set as the component's style when rendered. All
0144: * child styles should be calculated based on the the base style when the
0145: * component is rendered. This allows the component's style to be swapped by
0146: * only modifying the basse style. Default value is <code>null</code>.
0147: */
0148: protected String baseStyle;
0149:
0150: /**
0151: * The style used when a component is disabled. Default value is
0152: * "my-component-disabled".
0153: */
0154: protected String disabledStyle = "my-component-disabled";
0155:
0156: protected boolean rendered, disposed;
0157: protected Menu contextMenu;
0158: protected int style;
0159: protected Element focusElem;
0160: protected Rectangle attachBounds;
0161:
0162: private boolean hidden, disabled;
0163: private String id, cls, title;
0164: private Object data;
0165: private HashMap dataMap;
0166: private Observable observable;
0167: private String styles = "";
0168: private ToolTip toolTip;
0169: private int disableTextSelection = Style.DEFAULT;
0170: private int disableContextMenu = Style.DEFAULT;
0171: // cache size and location calls when widget is not attached
0172: private String attachHeight, attachWidth;
0173: private int borders = Style.DEFAULT;
0174: private String toolTipTitle, toolTipText;
0175:
0176: /**
0177: * Creates a new component instance.
0178: */
0179: public Component() {
0180: observable = new Observable();
0181: attachBounds = new Rectangle(-1, -1, -1, -1);
0182: }
0183:
0184: /**
0185: * Creates a new component instance with the given style.
0186: *
0187: * @param style the component's style information
0188: */
0189: public Component(int style) {
0190: this ();
0191: this .style = style;
0192: }
0193:
0194: /**
0195: * Adds a listener bound by the given event type.
0196: *
0197: * @param eventType the eventType
0198: * @param listener the listener to be added
0199: */
0200: public void addListener(int eventType, Listener listener) {
0201: observable.addListener(eventType, listener);
0202: }
0203:
0204: /**
0205: * Adds a CSS style name to the component's underlying element.
0206: *
0207: * @param style the CSS style name to add
0208: */
0209: public void addStyleName(String style) {
0210: if (rendered) {
0211: MyDOM.addStyleName(getStyleElement(), style);
0212: } else {
0213: cls = cls == null ? style : cls + " " + style;
0214: }
0215: }
0216:
0217: /**
0218: * Adds a listener to receive widget events.
0219: *
0220: * @param listener the listener to be added
0221: */
0222: public void addWidgetListener(WidgetListener listener) {
0223: TypedListener l = new TypedListener(listener);
0224: addListener(Events.Attach, l);
0225: addListener(Events.Detach, l);
0226: addListener(Events.Resize, l);
0227: }
0228:
0229: /**
0230: * Disable this component.
0231: */
0232: public void disable() {
0233: if (rendered) {
0234: onDisable();
0235: }
0236: disabled = true;
0237: fireEvent(Events.Disable);
0238: }
0239:
0240: /**
0241: * Enables and disables text selection for the component.
0242: *
0243: * @param disable <code>true</code> to disable text selection
0244: */
0245: public void disableTextSelection(boolean disable) {
0246: disableTextSelection = disable ? 1 : 0;
0247: if (isAttached()) {
0248: MyDOM.disableTextSelection(getElement(), disable);
0249: }
0250: }
0251:
0252: /**
0253: * Disposes this component by purging any event listeners, removing the
0254: * component's element from the DOM, removing the component from its parent
0255: * (if applicable). Subclasses should override as needed.
0256: */
0257: public void dispose() {
0258: if (fireEvent(Events.BeforeDispose)) {
0259: Widget p = getParent();
0260: if (p != null) {
0261: if (p instanceof HasWidgets) {
0262: ((HasWidgets) p).remove(this );
0263: } else if (p instanceof Container) {
0264: ((Container) p).remove(this );
0265: }
0266: }
0267:
0268: Element el = DOM.getParent(getElement());
0269: if (el != null) {
0270: DOM.removeChild(el, getElement());
0271: }
0272:
0273: if (getElement() != null) {
0274: clearElemenet();
0275: }
0276:
0277: disposed = true;
0278: disabled = true;
0279:
0280: onDestroy();
0281: fireEvent(Events.Dispose);
0282: removeAllListeners();
0283: observable = null;
0284: }
0285:
0286: }
0287:
0288: /**
0289: * Enable this component.
0290: */
0291: public void enable() {
0292: if (rendered) {
0293: onEnable();
0294: }
0295: disabled = false;
0296: fireEvent(Events.Enable);
0297: }
0298:
0299: /**
0300: * Enables or disables event processing.
0301: *
0302: * @param enable the enable state
0303: */
0304: public void enableEvents(boolean enable) {
0305: disabled = !enable;
0306: }
0307:
0308: /**
0309: * Fires an event.
0310: *
0311: * @param type the event type
0312: * @return <code>false</code> if any listeners return <code>false</code>
0313: */
0314: public boolean fireEvent(int type) {
0315: BaseEvent be = new BaseEvent();
0316: be.widget = this ;
0317: return fireEvent(type, be);
0318: }
0319:
0320: /**
0321: * Fires an event.
0322: *
0323: * @param type the event type
0324: * @param be the base event
0325: * @return <code>false</code> if any listeners return <code>false</code>
0326: */
0327: public boolean fireEvent(int type, BaseEvent be) {
0328: return observable.fireEvent(type, be);
0329: }
0330:
0331: /**
0332: * Fires an event.
0333: *
0334: * @param eventType the event type
0335: * @param widget the source widget
0336: * @param item the action widget
0337: * @return <code>true</code> if any listeners cancel the event
0338: */
0339: public boolean fireEvent(int eventType, Widget widget, Widget item) {
0340: BaseEvent be = new BaseEvent();
0341: be.widget = widget;
0342: be.item = item;
0343: return fireEvent(eventType, be);
0344: }
0345:
0346: /**
0347: * Fires an event.
0348: *
0349: * @param eventType the event type
0350: * @param widget the source widget
0351: * @param item the action widget
0352: * @param index the index
0353: * @return <code>true</code> if any listeners cancel the event
0354: */
0355: public boolean fireEvent(int eventType, Widget widget, Widget item,
0356: int index) {
0357: BaseEvent be = new BaseEvent();
0358: be.widget = widget;
0359: be.item = item;
0360: be.index = index;
0361: return fireEvent(eventType, be);
0362: }
0363:
0364: /**
0365: * Try to focus this component.
0366: *
0367: * @return this
0368: */
0369: public Component focus() {
0370: if (rendered) {
0371: if (!MyGWT.isSafari || focusElem == null) {
0372: MyDOM.setFocus(getElement(), true);
0373: } else {
0374: MyDOM.setFocus(focusElem, true);
0375: }
0376:
0377: }
0378: return this ;
0379: }
0380:
0381: /**
0382: * Returns the component's bounds.
0383: *
0384: * @return the component bounds
0385: */
0386: public Rectangle getBounds() {
0387: return MyDOM.getBounds(getElement());
0388: }
0389:
0390: /**
0391: * Returns the component's bounds.
0392: *
0393: * @param content <code>true</code> to adjust for box model issues
0394: * @return the elements bounds
0395: */
0396: public Rectangle getBounds(boolean content) {
0397: return MyDOM.getBounds(getElement(), content);
0398: }
0399:
0400: /**
0401: * Returns the application defined data associated with the component, or
0402: * <code>null</code> if it has not been set.
0403: */
0404: public Object getData() {
0405: return data;
0406: }
0407:
0408: /**
0409: * Returns the application defined property for the given name, or
0410: * <code>null</code> if it has not been set.
0411: *
0412: * @param key the name of the property
0413: * @return the value or <code>null</code> if it has not been set
0414: */
0415: public Object getData(String key) {
0416: if (dataMap == null)
0417: return null;
0418: return dataMap.get(key);
0419: }
0420:
0421: /**
0422: * Returns the disabled style.
0423: *
0424: * @return the disabled style
0425: */
0426: public String getDisabledStyle() {
0427: return disabledStyle;
0428: }
0429:
0430: public Element getElement() {
0431: if (!rendered) {
0432: render();
0433: }
0434: return super .getElement();
0435: }
0436:
0437: /**
0438: * Returns the component's height.
0439: *
0440: * @return the height
0441: */
0442: public int getHeight() {
0443: return MyDOM.getHeight(getElement(), false);
0444: }
0445:
0446: /**
0447: * Returns the component's height.
0448: *
0449: * @param content <code>true</code> to get the height minus borders and
0450: * padding
0451: * @return the height
0452: */
0453: public int getHeight(boolean content) {
0454: return MyDOM.getHeight(getElement(), content);
0455: }
0456:
0457: /**
0458: * Returns the component's id. If an id has not been set one will be created.
0459: *
0460: * @return the component's id
0461: */
0462: public String getId() {
0463: if (id == null) {
0464: id = MyDOM.getUniqueID();
0465: setId(id);
0466: return id;
0467: }
0468: return id;
0469: }
0470:
0471: /**
0472: * Returns the component's style information.
0473: *
0474: * @return the style information
0475: */
0476: public int getStyle() {
0477: return style;
0478: }
0479:
0480: /**
0481: * Returns the component's tool tip.
0482: *
0483: * @return the tool tip
0484: */
0485: public ToolTip getToolTip() {
0486: if (toolTip == null) {
0487: toolTip = new ToolTip(this );
0488: }
0489: return toolTip;
0490: }
0491:
0492: /**
0493: * Returns the component's width.
0494: *
0495: * @return the width
0496: */
0497: public int getWidth() {
0498: return MyDOM.getWidth(getElement(), true);
0499: }
0500:
0501: /**
0502: * Returns the component's width.
0503: *
0504: * @param content <code>true</code> to get the width minus borders and
0505: * padding
0506: * @return the component's width
0507: */
0508: public int getWidth(boolean content) {
0509: return MyDOM.getWidth(getElement(), content);
0510: }
0511:
0512: /**
0513: * Hide this component.
0514: */
0515: public void hide() {
0516: if (fireEvent(Events.BeforeHide)) {
0517: hidden = true;
0518: if (rendered) {
0519: onHide();
0520: }
0521: fireEvent(Events.Hide);
0522: }
0523: }
0524:
0525: /**
0526: * Returns <code>true</code> if the component is disposed.
0527: *
0528: * @return the dispose state
0529: */
0530: public boolean isDisposed() {
0531: return disposed;
0532: }
0533:
0534: /**
0535: * Returns <code>true</code> if the component is enabled.
0536: *
0537: * @return the enabled state
0538: */
0539: public boolean isEnabled() {
0540: return !disabled;
0541: }
0542:
0543: /**
0544: * Returns <code>true</code> if the component is rendered.
0545: *
0546: * @return the rendered state
0547: */
0548: public boolean isRendered() {
0549: return rendered;
0550: }
0551:
0552: /**
0553: * Returns <code>true</code> if the component is visible. A component is
0554: * visible if it is rendered and visible as defined by
0555: * {@link MyDOM#isVisible(Element)}.
0556: */
0557: public boolean isVisible() {
0558: return rendered && MyDOM.isVisible(getElement());
0559: }
0560:
0561: /**
0562: * Any events a component receives will be forwarded to this method.
0563: * Subclasses should override as needed. The {@link #onBrowserEvent} method
0564: * should not be overridden or modified.
0565: *
0566: * @param be the base event
0567: */
0568: public void onBaseEvent(BaseEvent be) {
0569:
0570: }
0571:
0572: /**
0573: * Components delegate event handling to {@link #onBaseEvent}. Sublcasses
0574: * should not override.
0575: *
0576: * @param event the dom event
0577: */
0578: public void onBrowserEvent(Event event) {
0579: if (disabled) {
0580: return;
0581: }
0582:
0583: BaseEvent be = new BaseEvent();
0584: be.type = DOM.eventGetType(event);
0585: be.event = event;
0586: be.widget = this ;
0587:
0588: if (be.type == Events.MouseUp && be.isRightClick()) {
0589: onRightClick(be);
0590: }
0591:
0592: if (!fireEvent(be.type, be)) {
0593: return;
0594: }
0595:
0596: onBaseEvent(be);
0597: }
0598:
0599: /**
0600: * Notifies the component that it should recalculate its layout based on its
0601: * current size if neccessary. Default implementation does nothing.
0602: */
0603: public void recalculate() {
0604:
0605: }
0606:
0607: /**
0608: * Removes all listeners.
0609: */
0610: public void removeAllListeners() {
0611: observable.removeAllListeners();
0612: }
0613:
0614: public void removeFromParent() {
0615: if (getParent() instanceof Container) {
0616: ((Container) getParent()).remove(this );
0617: return;
0618: }
0619: super .removeFromParent();
0620: }
0621:
0622: /**
0623: * Removes a listener.
0624: *
0625: * @param eventType the event type
0626: * @param listener the listener to be removed
0627: */
0628: public void removeListener(int eventType, Listener listener) {
0629: observable.removeListener(eventType, listener);
0630:
0631: }
0632:
0633: /**
0634: * Removes a CSS style name from the component's underlying element.
0635: *
0636: * @param style the CSS style name to remove
0637: */
0638: public void removeStyleName(String style) {
0639: if (rendered) {
0640: MyDOM.setStyleName(getStyleElement(), style, false);
0641: } else if (style != null && cls != null) {
0642: String[] s = cls.split(" ");
0643: cls = "";
0644: for (int i = 0; i < s.length; i++) {
0645: if (!s[i].equals(style)) {
0646: cls += " " + s[i];
0647: }
0648: }
0649: }
0650: }
0651:
0652: /**
0653: * Removes a previously added listener.
0654: *
0655: * @param listener the listener to be removed
0656: */
0657: public void removeWidgetListener(WidgetListener listener) {
0658: if (observable.eventTable == null)
0659: return;
0660: observable.eventTable.unhook(Events.Attach, listener);
0661: observable.eventTable.unhook(Events.Detach, listener);
0662: observable.eventTable.unhook(Events.Resize, listener);
0663: }
0664:
0665: /**
0666: * Adds or removes a border. The style name 'my-border' is added to the widget
0667: * to display a border.
0668: *
0669: * @param show the show state
0670: */
0671: public void setBorders(boolean show) {
0672: borders = show ? 1 : 0;
0673: if (isRendered()) {
0674: MyDOM.setBorders(getStyleElement(), show);
0675: }
0676: }
0677:
0678: /**
0679: * Sets the component's bounds.
0680: *
0681: * @param x the x coordinate
0682: * @param y the y coordinate
0683: * @param width the new width
0684: * @param height the new height
0685: */
0686: public void setBounds(int x, int y, int width, int height) {
0687: setSize(width, height);
0688: setPagePosition(x, y);
0689: }
0690:
0691: /**
0692: * Sets the component's bounds.
0693: *
0694: * @param rect the bounds
0695: */
0696: public void setBounds(Rectangle rect) {
0697: setBounds(rect.x, rect.y, rect.width, rect.height);
0698: }
0699:
0700: /**
0701: * Sets the application defined component data.
0702: *
0703: * @param data the widget data
0704: */
0705: public void setData(Object data) {
0706: this .data = data;
0707: }
0708:
0709: /**
0710: * Sets the application defined property with the given name.
0711: *
0712: * @param key the name of the property
0713: * @param data the new value for the property
0714: */
0715: public void setData(String key, Object data) {
0716: if (dataMap == null)
0717: dataMap = new HashMap();
0718: dataMap.put(key, data);
0719: }
0720:
0721: /**
0722: * Sets the disabled style. Default value is 'my-item-disabled'.
0723: *
0724: * @param style the disabled style
0725: */
0726: public void setDisabledStyle(String style) {
0727: this .disabledStyle = style;
0728: }
0729:
0730: // make public
0731: public void setElement(Element elem) {
0732: super .setElement(elem);
0733: }
0734:
0735: /**
0736: * Convenience function for setting disabled/enabled by boolean.
0737: *
0738: * @param enabled the enabled state
0739: */
0740: public void setEnabled(boolean enabled) {
0741: if (!enabled) {
0742: disable();
0743: } else {
0744: enable();
0745: }
0746: }
0747:
0748: /**
0749: * Sets the component's height.
0750: *
0751: * @param height the new height
0752: */
0753: public void setHeight(int height) {
0754: setSize(Style.DEFAULT, height);
0755: }
0756:
0757: /**
0758: * Sets the object's height. This height does not include decorations such as
0759: * border, margin, and padding.
0760: *
0761: * @param height the object's new height, in CSS units (e.g. "10px", "1em")
0762: */
0763: public void setHeight(String height) {
0764: if (rendered) {
0765: super .setHeight(height);
0766: onResize(Style.DEFAULT, Style.DEFAULT);
0767: } else {
0768: attachHeight = height;
0769: }
0770: }
0771:
0772: /**
0773: * Sets the component's id.
0774: *
0775: * @param id the new id
0776: */
0777: public void setId(String id) {
0778: this .id = id;
0779: if (rendered) {
0780: DOM.setElementProperty(getElement(), "id", id);
0781: }
0782: }
0783:
0784: /**
0785: * Sets a style attribute.
0786: *
0787: * @param attr the attribute
0788: * @param value the attribute value
0789: */
0790: public void setIntStyleAttribute(String attr, int value) {
0791: setStyleAttribute(attr, "" + value);
0792: }
0793:
0794: public void setPixelSize(int width, int height) {
0795: setSize(width, height);
0796: }
0797:
0798: /**
0799: * Sets the width and height of the component. This method fires the resize
0800: * event.
0801: *
0802: * @param width the new width
0803: * @param height the new height
0804: */
0805: public void setSize(int width, int height) {
0806: if (width != Style.DEFAULT) {
0807: attachBounds.width = width;
0808: }
0809: if (height != Style.DEFAULT) {
0810: attachBounds.height = height;
0811: }
0812: if (!rendered) {
0813: return;
0814: }
0815:
0816: MyDOM.setSize(getElement(), width, height, true);
0817:
0818: if (!isAttached()) {
0819: return;
0820: }
0821:
0822: onResize(width, height);
0823:
0824: BaseEvent be = new BaseEvent(this );
0825: be.width = width;
0826: be.height = height;
0827: fireEvent(Events.Resize, be);
0828: }
0829:
0830: /**
0831: * Sets the component's size. This size does not include decorations such as
0832: * border, margin, and padding.
0833: *
0834: * @param width the object's new width, in CSS units (e.g. "10px", "1em")
0835: * @param height the object's new height, in CSS units (e.g. "10px", "1em")
0836: */
0837: public void setSize(String width, String height) {
0838: setWidth(width);
0839: setHeight(height);
0840: }
0841:
0842: /**
0843: * Sets a style attribute.
0844: *
0845: * @param attr the attribute
0846: * @param value the attribute value
0847: */
0848: public void setStyleAttribute(String attr, String value) {
0849: if (rendered) {
0850: DOM.setStyleAttribute(getStyleElement(), attr, value);
0851: } else {
0852: styles += attr + ":" + value + ";";
0853: }
0854: }
0855:
0856: public void setStyleName(String style) {
0857: if (rendered) {
0858: super .setStyleName(style);
0859: } else {
0860: cls = style;
0861: }
0862: }
0863:
0864: public void setTitle(String title) {
0865: this .title = title;
0866: if (rendered) {
0867: super .setTitle(title);
0868: }
0869: }
0870:
0871: /**
0872: * Sets the component's tool tip.
0873: *
0874: * @param text the text
0875: */
0876: public void setToolTip(String text) {
0877: setToolTip(null, text);
0878: }
0879:
0880: /**
0881: * Sets the component's tool tip.
0882: *
0883: * @param title the title
0884: * @param text the text
0885: */
0886: public void setToolTip(String title, String text) {
0887: if (text == null && toolTip == null) {
0888: return;
0889: }
0890: toolTipTitle = title;
0891: toolTipText = text;
0892: if (rendered) {
0893: if (toolTip == null) {
0894: toolTip = new ToolTip(this );
0895: }
0896: toolTip.setText(title, text);
0897: }
0898:
0899: }
0900:
0901: /**
0902: * Convenience function to hide or show this component by boolean.
0903: *
0904: * @param visible the visible state
0905: */
0906: public void setVisible(boolean visible) {
0907: if (visible) {
0908: show();
0909: } else {
0910: hide();
0911: }
0912: }
0913:
0914: /**
0915: * Sets the component's width.
0916: *
0917: * @param width the width
0918: */
0919: public void setWidth(int width) {
0920: setSize(width, Style.DEFAULT);
0921: }
0922:
0923: /**
0924: * Sets the component's width. This width does not include decorations such as
0925: * border, margin, and padding.
0926: *
0927: * @param width the object's new width, in CSS units (e.g. "10px", "1em")
0928: */
0929: public void setWidth(String width) {
0930: if (rendered) {
0931: super .setWidth(width);
0932: onResize(Style.DEFAULT, Style.DEFAULT);
0933: } else {
0934: attachWidth = width;
0935: }
0936: }
0937:
0938: /**
0939: * Show this component.
0940: */
0941: public void show() {
0942: if (fireEvent(Events.BeforeShow)) {
0943: hidden = false;
0944: if (rendered) {
0945: onShow();
0946: }
0947: fireEvent(Events.Show);
0948: }
0949: }
0950:
0951: public void unhook(int type, EventListener listener) {
0952: if (observable.eventTable != null) {
0953: observable.eventTable.unhook(type, listener);
0954: }
0955: }
0956:
0957: /**
0958: * Called after the component has been rendered.
0959: */
0960: protected void afterRender() {
0961: if (attachBounds != null) {
0962: setSize(attachBounds.width, attachBounds.height);
0963: }
0964: }
0965:
0966: protected Component blur() {
0967: if (rendered) {
0968: MyDOM.setFocus(getElement(), false);
0969: }
0970: return this ;
0971: }
0972:
0973: /**
0974: * Enables and disables the component's context menu.
0975: *
0976: * @param disable <code>true</code> to disable the context menu
0977: */
0978: protected void disableContextMenu(boolean disable) {
0979: disableContextMenu = disable ? 1 : 0;
0980: if (isAttached()) {
0981: MyDOM.disableContextMenu(getElement(), disable);
0982: }
0983: }
0984:
0985: /**
0986: * Returns the component's context menu. This method is marked protected,
0987: * subclasses can change access to public to expose the contenxt menu.
0988: *
0989: * @return the context menu
0990: */
0991: protected Menu getContextMenu() {
0992: return contextMenu;
0993: }
0994:
0995: protected Element getFocusElement() {
0996: return focusElem == null ? getElement() : focusElem;
0997: }
0998:
0999: protected void onAttach() {
1000: if (!isRendered()) {
1001: render();
1002: }
1003: if (disableTextSelection > 0) {
1004: MyDOM.disableTextSelection(getElement(),
1005: disableTextSelection == 1);
1006: }
1007: if (disableContextMenu > 0) {
1008: MyDOM.disableContextMenu(getElement(),
1009: disableContextMenu == 1);
1010: }
1011: super .onAttach();
1012: }
1013:
1014: protected void onDestroy() {
1015:
1016: }
1017:
1018: protected void onDetach() {
1019: super .onDetach();
1020: if (disableTextSelection > 0) {
1021: MyDOM.disableTextSelection(getElement(), false);
1022: }
1023: if (disableContextMenu > 0) {
1024: MyDOM.disableContextMenu(getElement(), false);
1025: }
1026: fireEvent(Events.Detach);
1027: }
1028:
1029: protected void onDisable() {
1030: addStyleName(disabledStyle);
1031: }
1032:
1033: protected void onEnable() {
1034: removeStyleName(disabledStyle);
1035: }
1036:
1037: protected void onHide() {
1038: super .setVisible(false);
1039: }
1040:
1041: protected void onHideContextMenu() {
1042: disabled = false;
1043: }
1044:
1045: /**
1046: * Sets the page XY position of the component.
1047: *
1048: * @param x the x coordinate
1049: * @param y the y coordinate
1050: */
1051: public void setPagePosition(int x, int y) {
1052: if (x != Style.DEFAULT) {
1053: attachBounds.x = x;
1054: }
1055: if (y != Style.DEFAULT) {
1056: attachBounds.y = y;
1057: }
1058: if (!isAttached()) {
1059: return;
1060: }
1061:
1062: if (x != Style.DEFAULT) {
1063: MyDOM.setX(getElement(), x);
1064: }
1065: if (y != Style.DEFAULT) {
1066: MyDOM.setY(getElement(), y);
1067: }
1068: }
1069:
1070: protected void onLoad() {
1071: super .onLoad();
1072:
1073: if (attachHeight != null) {
1074: setHeight(attachHeight);
1075: attachHeight = null;
1076: }
1077:
1078: if (attachWidth != null) {
1079: setWidth(attachWidth);
1080: attachWidth = null;
1081: }
1082:
1083: if (attachBounds != null) {
1084: setSize(attachBounds.width, attachBounds.height);
1085: setPagePosition(attachBounds.x, attachBounds.y);
1086: }
1087: fireEvent(Events.Attach);
1088: }
1089:
1090: /**
1091: * Subclasses should override and ensure setElement is called.
1092: */
1093: protected void onRender() {
1094:
1095: }
1096:
1097: /**
1098: * Called whenever the component is resized. Default implementation calls
1099: * recalcuate.
1100: *
1101: * @param width the new width
1102: * @param height the new height
1103: */
1104: protected void onResize(int width, int height) {
1105: recalculate();
1106: }
1107:
1108: protected void onRightClick(final BaseEvent be) {
1109: if (contextMenu != null) {
1110: be.stopEvent();
1111: disabled = true;
1112: final int x = be.getClientX();
1113: final int y = be.getClientY();
1114: DeferredCommand.addCommand(new Command() {
1115: public void execute() {
1116: onShowContextMenu(x, y);
1117: }
1118: });
1119: }
1120: }
1121:
1122: protected void onShow() {
1123: super .setVisible(true);
1124: }
1125:
1126: protected void onShowContextMenu(int x, int y) {
1127: if (fireEvent(Events.ContextMenu)) {
1128: contextMenu.addListener(Events.Close, new Listener() {
1129: public void handleEvent(BaseEvent be) {
1130: contextMenu.removeListener(Events.Close, this );
1131: onHideContextMenu();
1132: }
1133: });
1134: contextMenu.show(x + 5, y + 5);
1135: disabled = true;
1136: }
1137: }
1138:
1139: /**
1140: * Renders the element. This method is not intended to be called directly.
1141: */
1142: protected void render() {
1143: rendered = true;
1144:
1145: onRender();
1146:
1147: if (cls != null) {
1148: addStyleName(cls);
1149: cls = null;
1150: }
1151:
1152: if (title != null) {
1153: setTitle(title);
1154: }
1155:
1156: if (id == null) {
1157: id = MyDOM.getUniqueID();
1158: }
1159: setId(id);
1160:
1161: if (styles != null) {
1162: MyDOM.applyStyles(getElement(), styles);
1163: styles = null;
1164: }
1165:
1166: if (toolTipText != null) {
1167: setToolTip(toolTipTitle, toolTipText);
1168: }
1169:
1170: if (hidden) {
1171: hide();
1172: }
1173:
1174: if (disabled) {
1175: disable();
1176: }
1177:
1178: if (borders != Style.DEFAULT) {
1179: setBorders(borders == 1);
1180: }
1181:
1182: if (((style & Style.FOCUSABLE) != 0) && MyGWT.isSafari) {
1183: focusElem = createHiddenInput();
1184: DOM.appendChild(getElement(), focusElem);
1185: }
1186:
1187: afterRender();
1188: fireEvent(Events.Render);
1189: }
1190:
1191: /**
1192: * Sets the component's context menu.
1193: *
1194: * @param menu the context menu
1195: */
1196: protected void setContextMenu(Menu menu) {
1197: contextMenu = menu;
1198: disableContextMenu(true);
1199: if (isAttached()) {
1200: MyDOM.disableContextMenu(getElement(), true);
1201: }
1202: }
1203:
1204: private native void clearElemenet() /*-{
1205: this.@com.google.gwt.user.client.ui.UIObject::element = null;
1206: }-*/;
1207:
1208: private native Element createHiddenInput() /*-{
1209: var input = $doc.createElement('input');
1210: input.type = 'text';
1211: input.style.opacity = 0;
1212: input.style.zIndex = -1;
1213: input.style.height = '1px !important';
1214: input.style.width = '1px !important';
1215: input.style.overflow = 'hidden !important';
1216: input.style.position = 'absolute !important';
1217: input.style.left = '0px !important';
1218: input.style.top = '0px !important';
1219: return input;
1220: }-*/;
1221:
1222: }
|