Package com.extjs.gxt.ui.client.widget

Source Code of com.extjs.gxt.ui.client.widget.Component

/*
* Ext GWT - Ext for GWT
* Copyright(c) 2007, 2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
package com.extjs.gxt.ui.client.widget;

import java.util.HashMap;
import java.util.Map;

import com.extjs.gxt.ui.client.Events;
import com.extjs.gxt.ui.client.GXT;
import com.extjs.gxt.ui.client.Style;
import com.extjs.gxt.ui.client.XDOM;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.BaseObservable;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.Observable;
import com.extjs.gxt.ui.client.event.WidgetListener;
import com.extjs.gxt.ui.client.state.StateManager;
import com.extjs.gxt.ui.client.widget.layout.LayoutData;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.tips.ToolTip;
import com.extjs.gxt.ui.client.widget.tips.ToolTipConfig;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;

/**
* Base class for GXT components. All subclasses of Component can automatically
* participate in the standard GXT component lifecycle of creation, attach and
* detach. They also have automatic support for basic hide/show and
* enable/disable behavior. Component allows any subclass to be lazy-rendered
* into any GXT {@link Container}. Components added to a GWT {@link Panel} will
* be rendered when inserted. All visual widgets that require rendering into a
* layout should subclass Component (or {@link BoxComponent} if managed box
* model handling is required).
*
* <p>
* The following 4 methods inherited from UIObject (setSize, setWidth,
* setHeight, setPixelSize) have been overridden and do nothing. Any component
* whose size can change should subclass {@link BoxComponent}.
* </p>
*
* <dl>
* <dt>Events:</dt>
*
* <dd><b>Enable</b> : ComponentEvent(component)<br>
* <div>Fires after the component is enabled.</div>
* <ul>
* <li>component : this</li>
* </ul>
* </dd>
*
* <dd><b>Disable</b> : ComponentEvent(component)<br>
* <div>Fires after the component is disabled.</div>
* <ul>
* <li>component : this</li>
* </ul>
* </dd>
*
* <dd><b>BeforeHide</b> : ComponentEvent(component)<br>
* <div>Fires before the component is hidden. Listeners can set the
* <code>doit</code> field to <code>false</code> to cancel the action.</div>
* <ul>
* <li>component : this</li>
* </ul>
* </dd>
*
* <dd><b>BeforeShow</b> : ComponentEvent(component)<br>
* <div>Fires before the component is shown. Listeners can set the
* <code>doit</code> field to <code>false</code> to cancel the action.</div>
* <ul>
* <li>component : this</li>
* </ul>
* </dd>
*
* <dd><b>Hide</b> : ComponentEvent(component)<br>
* <div>Fires after the component is hidden.</div>
* <ul>
* <li>component : this</li>
* </ul>
* </dd>
*
* <dd><b>Show</b> : ComponentEvent(component)<br>
* <div>Fires after the component is shown.</div>
* <ul>
* <li>component : this</li>
* </ul>
* </dd>
*
* <dd><b>Attach</b> : ComponentEvent(component)<br>
* <div>Fires after the component is attached.</div>
* <ul>
* <li>component : this</li>
* </ul>
* </dd>
*
* <dd><b>Detach</b> : ComponentEvent(component) <br>
* <div>Fires after the component is detached.</div>
* <ul>
* <li>component : this</li>
* </ul>
* </dd>
*
* <dd><b>BeforeRender</b> : ComponentEvent(component)<br>
* <div>Fires before the component is rendered. Listeners can set the
* <code>doit</code> field to <code>false</code> to cancel the action.</div>
* <ul>
* <li>component : this</li>
* </ul>
* </dd>
*
* <dd><b>Render</b> : ComponentEvent(component)<br>
* <div>Fires after the component is rendered.</div>
* <ul>
* <li>component : this</li>
* </ul>
* </dd>
*
* <dd><b>BrowserEvent</b> : ComponentEvent(component, event)<br>
* <div>Fires on any browser event the component receives. Listners will be
* called prior to any event processing and before
* {@link #onComponentEvent(ComponentEvent)} is called. Listeners can set the
* <code>doit</code> field to <code>false</code> to cancel the processing of
* the event.</div>
* <ul>
* <li>component : this</li>
* <li>event : event</li>
* </ul>
* </dd>
*
* <dd><b>BeforeStateRestore</b> : ComponentEvent(component, state)<br>
* <div>Fires before the state of the component is restored. Listeners can set
* the <code>doit</code> field to <code>false</code> to cancel the action.</div>
* <ul>
* <li>component : this</li>
* <li>state : the state values
* </ul>
* </dd>
*
* <dd><b>StateRestore</b> : ComponentEvent(component, state)<br>
* <div>Fires after the state of the component is restored.</div>
* <ul>
* <li>component : this</li>
* <li>state : map of state key / value pairs</li>
* </ul>
* </dd>
*
* <dd><b>StateRestore</b> : ComponentEvent(component, state)<br>
* <div>Fires before the state of the component is saved to the configured state
* provider.</div>
* <ul>
* <li>component : this</li>
* <li>state : map of state key / value pairs</li>
* </ul>
* </dd>
*
* <dd><b>StateSave</b> : ComponentEvent(component, state)<br>
* <div>Fires after the state of the component is saved to the configured state
* provider.</div>
* <ul>
* <li>component : this</li>
* <li>state : map of state key / value pairs</li>
* </ul>
* </dd>
*
* </dl>
*/
public abstract class Component extends Widget implements Observable {

  static {
    GXT.init();
  }

  /**
   * The base style is typically set as the component's style when rendered. All
   * child styles should be calculated based on the base style when the
   * component is rendered. This allows a component's style to be swapped by
   * simply modifying the base style (defaults to null).
   */
  protected String baseStyle;

  /**
   * The style used when a component is disabled (defaults to
   * 'x-item-disabled').
   */
  protected String disabledStyle = "x-item-disabled";

  /**
   * True if this component has been rendered. Read-only.
   */
  protected boolean rendered;

  /**
   * True if the component is can receive focus (defaults to false). A hidden
   * input field will be created created for Safari.
   */
  protected boolean focusable;

  /**
   * True if this component is hidden. Read only.
   */
  protected boolean hidden;

  /**
   * True if the component is disabled. Read only.
   */
  protected boolean disabled;

  /**
   * True to enable state (defaults to true).
   */
  protected boolean stateful = true;

  /**
   * The state id (defaults to null).
   */
  protected String stateId;

  protected boolean hasListeners;
  protected ToolTip toolTip;

  private El el;
  private Map<String, Object> state;
  private ToolTipConfig toolTipConfig;
  private Menu contextMenu;
  private String id, itemId, cls, title;
  private Object data;
  private HashMap dataMap;
  private BaseObservable observable;
  private String styles = "";
  private int disableTextSelection = Style.DEFAULT;
  private int disableContextMenu = Style.DEFAULT;
  private int borders = Style.DEFAULT;
  private El focusEl;
  private Map overElements;
  private Element dummy;
  private boolean disableEvents;
  private boolean hasBrowserListener;
  private boolean enableState = true;
  private boolean focused;
  private boolean afterRender;
  private boolean setElementRender;
  private LayoutData layoutData;
  private ModelData model;

  /**
   * Creates a new component..
   */
  public Component() {
    observable = new BaseObservable();
  }

  /**
   * Specialized constructor for creating components from existing nodes. The
   * given element should be part of the dom and have a a parent element.
   *
   * @param element the element
   * @param attach true to attach the component
   */
  protected Component(Element element, boolean attach) {
    this();
    setElement(element);
    render(DOM.getParent(element));
    if (attach) {
      onAttach();
    }
  }

  /**
   * Appends an event handler to this component.
   *
   * @param eventType the eventType
   * @param listener the listener to be added
   */
  public void addListener(int eventType, Listener listener) {
    hasListeners = true;
    if (eventType == Events.BrowserEvent) {
      hasBrowserListener = true;
    }
    observable.addListener(eventType, listener);
  }

  /**
   * Adds a CSS style name to the component's underlying element.
   *
   * @param style the CSS style name to add
   */
  public void addStyleName(String style) {
    if (rendered) {
      fly(getStyleElement()).addStyleName(style);
    } else {
      cls = cls == null ? style : cls + " " + style;
    }
  }

  /**
   * Adds a listener to receive widget events.
   *
   * @param listener the listener to be added
   */
  public void addWidgetListener(WidgetListener listener) {
    addListener(Events.Attach, listener);
    addListener(Events.Detach, listener);
    addListener(Events.Resize, listener);
  }

  /**
   * Disable this component. Fires the <i>Disable</i> event.
   */
  public void disable() {
    if (rendered) {
      onDisable();
    }
    disabled = true;
    fireEvent(Events.Disable);
  }

  /**
   * True to disable event processing.
   *
   * @param disable true to disable
   */
  public void disableEvents(boolean disable) {
    disableEvents = disable;
  }

  /**
   * Enables and disables text selection for the component.
   *
   * @param disable <code>true</code> to disable text selection
   */
  public void disableTextSelection(boolean disable) {
    disableTextSelection = disable ? 1 : 0;
    if (isAttached()) {
      el.disableTextSelection(disable);
    }
  }

  /**
   * Returns the component's el instance.
   *
   * @return the el instance
   */
  public El el() {
    return el;
  }

  /**
   * Enable this component. Fires the <i>Enable</i> event.
   */
  public void enable() {
    if (rendered) {
      onEnable();
    }
    disabled = false;
    fireEvent(Events.Enable);
  }

  /**
   * Enables or disables event processing.
   *
   * @param enable the enable state
   */
  public void enableEvents(boolean enable) {
    disabled = !enable;
  }

  /**
   * Fires an event with the given event type.
   *
   * @param type the event type
   * @return <code>false</code> if any listeners return <code>false</code>
   */
  public boolean fireEvent(int type) {
    ComponentEvent be = createComponentEvent(null);
    be.type = type;
    return fireEvent(type, be);
  }

  public boolean fireEvent(int eventType, BaseEvent be) {
    return observable.fireEvent(eventType, be);
  }

  /**
   * Fires the specified event with the given event type.
   *
   * @param type the event type
   * @param ce the base event
   * @return <code>false</code> if any listeners return <code>false</code>
   */
  public boolean fireEvent(int type, ComponentEvent ce) {
    return observable.fireEvent(type, ce);
  }

  /**
   * Returns the global flyweight instance.
   *
   * @param elem the new wrapped dom element
   * @return the global flyweight instance
   */
  public El fly(Element elem) {
    return El.fly(elem);
  }

  /**
   * Try to focus this component. Fires the <i>Focus</i> event.
   */
  public void focus() {
    this.focused = true;
    if (rendered) {
      getFocusEl().focus();
    }
    fireEvent(Events.Focus);
  }

  /**
   * Returns the component's base style.
   *
   * @return the base style
   */
  public String getBaseStyle() {
    return baseStyle;
  }

  /**
   * Returns the component's border state.
   *
   * @return true if borders are visisble
   */
  public boolean getBorders() {
    return borders > 0;
  }

  /**
   * Returns the application defined data associated with the component, or
   * <code>null</code> if it has not been set.
   *
   * @return the data
   * @deprecated Use {@link #getData(String)}
   */
  public Object getData() {
    return data;
  }

  /**
   * Returns the application defined property for the given name, or
   * <code>null</code> if it has not been set.
   *
   * @param key the name of the property
   * @return the value or <code>null</code> if it has not been set
   */
  public <X> X getData(String key) {
    if (dataMap == null) return null;
    return (X) dataMap.get(key);
  }

  @Override
  public Element getElement() {
    // if getElement is called before a component is rendered then the caller is
    // a gwt panel. a proxy element is returned and the component will be
    // rendered when it is attached
    if (!rendered) {
      dummy = DOM.createDiv();
      return dummy;
    }
    return super.getElement();
  }

  /**
   * Returns the id of this component. A new id is generated if an id has not
   * been set.
   *
   * @return the component's id
   */
  public String getId() {
    if (id == null) {
      id = XDOM.getUniqueId();
      setId(id);
      return id;
    }
    return id;
  }

  /**
   * Returns the item id of this component. Unlike the component's id, the item
   * id does not have to be unique.
   *
   * @return the component's item id
   */
  public String getItemId() {
    return itemId != null ? itemId : getId();
  }


  protected LayoutData getLayoutData() {
    return layoutData;
  }

  /**
   * Returns the component's model.
   *
   * @return the model
   */
  public ModelData getModel() {
    return model;
  }

  /**
   * Returns the component's state.
   *
   * @return the state
   */
  public Map<String, Object> getState() {
    if (!enableState || state == null) {
      state = new HashMap<String, Object>();
    }
    return state;
  }

  /**
   * Returns the component's tool tip.
   *
   * @return the tool tip
   */
  public ToolTip getToolTip() {
    if (toolTip == null && toolTipConfig != null) {
      toolTip = new ToolTip(this, toolTipConfig);
    }
    return toolTip;
  }

  /**
   * Hide this component. Fires the <i>BeforeHide</i> event before the
   * component is hidden, the fires the <i>Hide</i> event after the component
   * is hidden.
   */
  public void hide() {
    if (fireEvent(Events.BeforeHide)) {
      hidden = true;
      if (rendered) {
        onHide();
      }
      fireEvent(Events.Hide);
    }
  }

  /**
   * Hides the component's tool tip (if one exists).
   */
  public void hideToolTip() {
    if (toolTip != null) {
      toolTip.hide();
    }
  }

  /**
   * Returns <code>true</code> if the component is enabled.
   *
   * @return the enabled state
   */
  public boolean isEnabled() {
    return !disabled;
  }

  /**
   * Returns <code>true</code> if the component is rendered.
   *
   * @return the rendered state
   */
  public boolean isRendered() {
    return rendered;
  }

  /**
   * Returns <code>true</code> if the component is visible.
   */
  public boolean isVisible() {
    return rendered && el.isVisible();
  }

  /**
   * Components delegate event handling to
   * {@link #onComponentEvent(ComponentEvent)}. Sublcasses should not override.
   *
   * @param event the dom event
   */
  public void onBrowserEvent(Event event) {
    if (disabled || disableEvents) {
      return;
    }

    int type = DOM.eventGetType(event);

    // hack to receive keyboard events in safari
    if (GXT.isSafari && type == Event.ONCLICK && focusable) {
      focus();
    }

    ComponentEvent ce = createComponentEvent(event);
    ce.event = event;

    // browser event listeners can cancel event
    if (hasBrowserListener && !fireEvent(Events.BrowserEvent, ce)) {
      return;
    }

    // dom event type
    ce.type = type;

    // listeners can cancel event
    if (hasListeners && !fireEvent(ce.type, ce)) {
      return;
    }

    int tt = GXT.isSafari ? Event.ONMOUSEDOWN : Event.ONMOUSEUP;
    if (ce.type == tt && ce.isRightClick()) {
      onRightClick(ce);
    }

    // specialized support for mouse overs
    int t = ce.type;
    if (overElements != null && (t == Event.ONMOUSEOVER || t == Event.ONMOUSEOUT)) {
      El target = fly(ce.getTarget());
      String id = target.getId();
      if (id != null && overElements.containsKey(id)) {
        String style = (String) overElements.get(id);
        target.setStyleName(style, t == Event.ONMOUSEOVER);
      }
    }

    onComponentEvent(ce);
  }

  /**
   * Any events a component receives will be forwarded to this method.
   * Subclasses should override as needed. The {@link #onBrowserEvent} method
   * should not be overridden or modified.
   *
   * @param ce the base event
   */
  public void onComponentEvent(ComponentEvent ce) {
  }

  /**
   * Called when the component is in a LayoutContainer and the container's
   * layout executes. This method will not be called on container instances.
   * Default implementation does nothing.
   */
  public void recalculate() {

  }

  /**
   * Removes all listeners.
   */
  public void removeAllListeners() {
    observable.removeAllListeners();
  }

  @Override
  public void removeFromParent() {
    if (getParent() instanceof Container) {
      ((Container) getParent()).remove(this);
      return;
    }
    super.removeFromParent();
  }

  /**
   * Removes a listener.
   *
   * @param eventType the event type
   * @param listener the listener to be removed
   */
  public void removeListener(int eventType, Listener listener) {
    observable.removeListener(eventType, listener);
    hasListeners = observable.hasListeners();
  }

  /**
   * Removes a CSS style name from the component's underlying element.
   *
   * @param style the CSS style name to remove
   */
  public void removeStyleName(String style) {
    if (rendered) {
      fly(getStyleElement()).removeStyleName(style);
    } else if (style != null) {
      String[] s = style.split(" ");
      style = "";
      for (int i = 0; i < s.length; i++) {
        if (!s[i].equals(style)) {
          style += " " + s[i];
        }
      }
    }
  }

  /**
   * Removes a listener.
   *
   * @param listener the listener to be removed
   */
  public void removeWidgetListener(WidgetListener listener) {
    if (observable.hasListeners()) {
      observable.removeListener(Events.Attach, listener);
      observable.removeListener(Events.Detach, listener);
      observable.removeListener(Events.Resize, listener);
    }
  }

  /**
   * Renders the element. Typically, this method does not need to be called
   * directly. A component will rendered by its parent if it is a container, or
   * rendered when attached if added to a gwt panel.
   *
   * @param target the element this component should be rendered into
   */
  public void render(Element target) {
    render(target, -1);
  }

  /**
   * Renders the element. Typically, this method does not need to be called
   * directly. A component will rendered by its parent if it is a container, or
   * rendered when attached if added to a gwt panel.
   *
   * @param target the element this component should be rendered into
   * @param index the index within the container <b>before</b> which this
   *          component will be inserted (defaults to appending to the end of
   *          the container if value is -1)
   */
  public void render(Element target, int index) {
    if (rendered || !fireEvent(Events.BeforeRender)) {
      return;
    }

    beforeRender();

    rendered = true;

    createStyles(baseStyle);

    if (!setElementRender) {
      if (index == -1) {
        index = DOM.getChildCount(target);
      }

      onRender(target, index);
    }

    if (el == null)
      throw new RuntimeException(getClass().getName() + " must call setElement in onRender");

    if (id == null) {
      id = el.getId();
      if (id == null || id.equals("")) {
        id = XDOM.getUniqueId();
      }
    }
    getElement().setId(id);

    initState();

    addStyleName(baseStyle);

    if (cls != null) {
      addStyleName(cls);
      cls = null;
    }

    if (title != null) {
      setTitle(title);
    }

    if (styles != null && !styles.equals("")) {
      el.applyStyles(styles);
      styles = null;
    }

    if (toolTipConfig != null) {
      setToolTip(toolTipConfig);
    }

    if (hidden) {
      hide();
    }

    if (disabled) {
      disable();
    }

    if (focused) {
      focus();
    }

    if (borders != Style.DEFAULT) {
      setBorders(borders == 1);
    }

    if (focusable && GXT.isSafari) {
      focusEl = new El(createHiddenInput());
      getElement().appendChild(focusEl.dom);
    }

    afterRender = true;
    afterRender();

    fireEvent(Events.Render);
  }

  /**
   * Saves the component's current state.
   */
  public void saveState() {
    if (enableState && state != null) {
      ComponentEvent ce = createComponentEvent(null);
      ce.state = state;
      if (fireEvent(Events.BeforeStateSave, ce)) {
        String sid = stateId != null ? stateId : getId();
        StateManager.get().set(sid, state);
        fireEvent(Events.StateSave, ce);
      }
    }
  }

  /**
   * Adds or removes a border. The style name 'x-border' is added to the widget
   * to display a border.
   *
   * @param show <code>true</code> to display a border
   */
  public void setBorders(boolean show) {
    borders = show ? 1 : 0;
    if (rendered) {
      fly(getStyleElement()).setBorders(show);
    }
  }

  /**
   * Sets the application defined component data.
   *
   * @param data the widget data
   * @deprecated use {@link #setData(String, Object)}
   */
  public void setData(Object data) {
    if (data instanceof LayoutData) {
      throw new IllegalArgumentException("Use setLayoutData to set layout data");
    }
    if (data instanceof ModelData) {
      throw new IllegalArgumentException("Use setModel to set models");
    }
    this.data = data;
  }

  /**
   * Sets the application defined property with the given name.
   *
   * @param key the name of the property
   * @param data the new value for the property
   */
  public void setData(String key, Object data) {
    if (dataMap == null) dataMap = new HashMap();
    dataMap.put(key, data);
  }

  // make public
  public void setElement(Element elem) {
    el = new El(elem);
    super.setElement(elem);
    if (!rendered) {
      setElementRender = true;
      render(null);
    }
  }

  /**
   * Convenience function for setting disabled/enabled by boolean.
   *
   * @param enabled the enabled state
   */
  public void setEnabled(boolean enabled) {
    if (!enabled) {
      disable();
    } else {
      enable();
    }
  }

  /**
   * Sets whether the component's state is enabled (defaults to true).
   *
   * @param enable true to enable
   */
  public void setEnableState(boolean enable) {
    this.enableState = enable;
  }

  /**
   * Overrides UIObject and does nothing.
   */
  public void setHeight(String height) {
  }

  /**
   * Sets the component's id.
   *
   * @param id the new id
   */
  public void setId(String id) {
    this.id = id;
    if (el != null) {
      DOM.setElementProperty(getElement(), "id", id);
    }
  }

  /**
   * Sets a style attribute.
   *
   * @param attr the attribute
   * @param value the attribute value
   */
  public void setIntStyleAttribute(String attr, int value) {
    setStyleAttribute(attr, "" + value);
  }

  /**
   * Sets the component's item id.
   *
   * @param id the item id
   */
  public void setItemId(String id) {
    this.itemId = id;
  }

  /**
   * Overrides UIObject and does nothing.
   */
  public void setPixelSize(int width, int height) {
  }

  /**
   * Overrides UIObject and does nothing.
   */
  public void setSize(String width, String height) {
  }

  /**
   * Sets a style attribute.
   *
   * @param attr the attribute
   * @param value the attribute value
   */
  public void setStyleAttribute(String attr, String value) {
    if (rendered) {
      DOM.setStyleAttribute(getStyleElement(), attr, value);
    } else {
      styles += attr + ":" + value + ";";
    }
  }

  @Override
  public void setStyleName(String style) {
    if (rendered) {
      super.setStyleName(style);
    } else {
      cls = style;
    }
  }

  @Override
  public void setTitle(String title) {
    this.title = title;
    if (rendered) {
      super.setTitle(title);
    }
  }

  /**
   * Sets the component's tool tip.
   *
   * @param text the text
   */
  public void setToolTip(String text) {
    if (toolTipConfig == null) {
      toolTipConfig = new ToolTipConfig();
    }
    toolTipConfig.setText(text);
    setToolTip(toolTipConfig);
  }

  /**
   * Sets the component's tool tip with the given config.
   *
   * @param config the tool tip config
   */
  public void setToolTip(ToolTipConfig config) {
    this.toolTipConfig = config;
    if (rendered) {
      if (toolTip == null) {
        toolTip = new ToolTip(this, config);
      } else {
        toolTip.update(config);
      }
    }
  }

  /**
   * Convenience function to hide or show this component by boolean.
   *
   * @param visible the visible state
   */
  public void setVisible(boolean visible) {
    if (visible) {
      show();
    } else {
      hide();
    }
  }

  /**
   * Overrides UIObject and does nothing.
   */
  public void setWidth(String width) {
  }

  /**
   * Show this component. Fires the <i>BeforeShow</i> event before the
   * component is made visible, then fires the <i>Show</i> event after the
   * component is visible.
   */
  public void show() {
    if (fireEvent(Events.BeforeShow)) {
      hidden = false;
      if (rendered) {
        onShow();
      }
      fireEvent(Events.Show);
    }
  }

  @Override
  public String toString() {
    return el != null ? el.toString() : super.toString();
  }

  /**
   * Adds a style to the given element on mousever. The component must be
   * sinking mouse events for the over style to function.
   *
   * @param elem the over element
   * @param style the style to add
   */
  protected void addStyleOnOver(Element elem, String style) {
    if (overElements == null) {
      overElements = new HashMap();
    }
    String id = null;
    if (getElement() == elem) {
      id = getId();
    } else {
      id = fly(elem).getId();
      if (id == null || id.equals("")) {
        id = XDOM.getUniqueId();
        fly(elem).dom.setId(id);
      }
    }
    overElements.put(id, style);
  }

  /**
   * Called after the component has been rendered and is attached for the first
   * time. At this time, the component will be part of the DOM which is required
   * when retrieving location and offsets.
   */
  protected void afterRender() {

  }

  protected void applyState(Map<String, Object> state) {

  }

  protected void assertPreRender() {
    assert !afterRender : "Method must be called before the component is rendered";
  }

  /**
   * Called before the component has been rendered.
   *
   * <p/> This method can be used to lazily alter this component pre-render
   */
  protected void beforeRender() {
  }

  /**
   * Tries to remove focus from the component. Fires the <i>Blur</i> event.
   */
  protected void blur() {
    if (rendered) {
      getFocusEl().blur();
    }
    fireEvent(Events.Blur);
  }

  protected ComponentEvent createComponentEvent(Event event) {
    return new ComponentEvent(this, event);
  }

  protected void createStyles(String baseStyle) {

  }

  /**
   * Enables and disables the component's context menu.
   *
   * @param disable <code>true</code> to disable the context menu
   */
  protected void disableContextMenu(boolean disable) {
    disableContextMenu = disable ? 1 : 0;
    if (isAttached()) {
      el.disableContextMenu(disable);
    }
  }

  /**
   * Returns the component's context menu. This method is marked protected,
   * subclasses can change access to public to expose the contenxt menu.
   *
   * @return the context menu
   */
  protected Menu getContextMenu() {
    return contextMenu;
  }

  protected El getFocusEl() {
    return focusEl == null ? el : focusEl;
  }

  protected void initState() {
    String sid = stateId != null ? stateId : getId();
    state = StateManager.get().getMap(sid);
    if (state != null) {
      ComponentEvent ce = createComponentEvent(null);
      ce.state = state;
      if (fireEvent(Events.BeforeStateRestore, ce)) {
        applyState(state);
        fireEvent(Events.StateRestore, ce);
      }
    }
  }

  @Override
  protected void onAttach() {
    // added to a gwt panel, not rendered
    if (!rendered) {
      // render and swap the proxy element
      Element parent = DOM.getParent(dummy);
      int index = DOM.getChildIndex(parent, dummy);
      DOM.removeChild(parent, dummy);
      render(parent, index);
    }
    if (disableTextSelection > 0) {
      el.disableTextSelection(disableTextSelection == 1);
    }
    if (disableContextMenu > 0) {
      el.disableContextMenu(disableContextMenu == 1);
    }
    super.onAttach();
  }

  @Override
  protected void onDetach() {
    super.onDetach();
    if (disableTextSelection > 0) {
      el.disableTextSelection(false);
    }
    if (disableContextMenu > 0) {
      el.disableContextMenu(false);
    }
    fireEvent(Events.Detach);
  }

  protected void onDisable() {
    addStyleName(disabledStyle);
  }

  protected void onEnable() {
    removeStyleName(disabledStyle);
  }

  protected void onHide() {
    el.setVisible(false);
  }

  protected void onHideContextMenu() {
    disableEvents = false;
  }

  @Override
  protected void onLoad() {
    super.onLoad();
    fireEvent(Events.Attach);
  }

  /**
   * Subclasses must override and ensure setElement is called for lazy rendered
   * components.
   *
   * @param target the target element
   * @param index the insert location
   */
  protected void onRender(Element target, int index) {

  }

  protected void onRightClick(final ComponentEvent ce) {
    if (contextMenu != null) {
      ce.stopEvent();
      final int x = ce.getClientX();
      final int y = ce.getClientY();
      if (fireEvent(Events.ContextMenu, ce)) {
        DeferredCommand.addCommand(new Command() {
          public void execute() {
            onShowContextMenu(x, y);
          }
        });
      }
    }
  }

  protected void onShow() {
    el.setVisible(true);
  }

  protected void onShowContextMenu(int x, int y) {
    contextMenu.addListener(Events.Hide, new Listener<ComponentEvent>() {
      public void handleEvent(ComponentEvent ce) {
        contextMenu.removeListener(Events.Hide, this);
        onHideContextMenu();
      }
    });
    contextMenu.showAt(x + 5, y + 5);
    disableEvents = true;
  }

  protected void removeStyleOnOver(Element elem) {
    if (overElements != null) {
      overElements.remove(fly(elem).getId());
    }
  }

  /**
   * Sets the component's context menu.
   *
   * @param menu the context menu
   */
  protected void setContextMenu(Menu menu) {
    contextMenu = menu;
    disableContextMenu(true);
    if (isAttached()) {
      el.disableContextMenu(true);
    }
  }

  protected void setEl(El el) {
    this.el = el;
  }

  protected void setElement(Element elem, Element parent, int index) {
    setElement(elem);
    DOM.insertChild(parent, elem, index);
  }

  protected void setFiresEvents(boolean firesEvents) {
    observable.setFiresEvents(firesEvents);
  }

  protected void setLayoutData(LayoutData data) {
    this.layoutData = data;
  }

  protected void setModel(ModelData model) {
    this.model = model;
  }

  private native Element createHiddenInput() /*-{
   var input = $doc.createElement('input');
   input.type = 'text';
   input.style.opacity = 0;
   input.style.zIndex = -1;
   input.style.height = '1px';
   input.style.width = '1px';
   input.style.overflow = 'hidden';
   input.style.position = 'absolute';
   return input;
   }-*/;
}
 
TOP

Related Classes of com.extjs.gxt.ui.client.widget.Component

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.