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

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

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

import java.util.ArrayList;
import java.util.List;

import com.extjs.gxt.ui.client.GXT;
import com.extjs.gxt.ui.client.Style;
import com.extjs.gxt.ui.client.aria.FocusFrame;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.core.FastMap;
import com.extjs.gxt.ui.client.core.XDOM;
import com.extjs.gxt.ui.client.event.BoxComponentEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.util.Point;
import com.extjs.gxt.ui.client.util.Rectangle;
import com.extjs.gxt.ui.client.util.Size;
import com.extjs.gxt.ui.client.util.Util;
import com.extjs.gxt.ui.client.widget.Layer.ShadowPosition;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;

/**
* Base class for any visual {@link Component} that uses a box container.
* {@link BoxComponent} provides automatic box model adjustments for sizing and
* positioning and will work correctly within the {@link Component} rendering
* model.
*
* <dl>
* <dt><b>Events:</b></dt>
*
* <dd><b>Resize</b> : BoxComponentEvent(boxComponent, width, height)<br>
* <div>Fires after the component is resized.</div>
* <ul>
* <li>boxComponent : this</li>
* <li>width : the widget width</li>
* <li>height : the widget height</li>
* </ul>
*
* <dd><b>Move</b> : BoxComponentEvent(boxComponent, x, y)<br>
* <div>Fires after the component is moved.</div>
* <ul>
* <li>boxComponent : this</li>
* <li>x : the new x position</li>
* <li>y : the new y position</li>
* </ul>
* </dd>
* </dl>
*
* <dl>
* <dt>Inherited Events:</dt>
* <dd>Component Enable</dd>
* <dd>Component Disable</dd>
* <dd>Component BeforeHide</dd>
* <dd>Component Hide</dd>
* <dd>Component BeforeShow</dd>
* <dd>Component Show</dd>
* <dd>Component Attach</dd>
* <dd>Component Detach</dd>
* <dd>Component BeforeRender</dd>
* <dd>Component Render</dd>
* <dd>Component BrowserEvent</dd>
* <dd>Component BeforeStateRestore</dd>
* <dd>Component StateRestore</dd>
* <dd>Component BeforeStateSave</dd>
* <dd>Component SaveState</dd>
* </dl>
*/
public class BoxComponent extends Component {

  /**
   * True to adjust sizes for box model issues to ensure actual size matches set
   * size.
   */
  protected boolean adjustSize = true;

  /**
   * True to enable a shim which uses a transparent iframe to stop content from
   * bleeding through.
   */
  protected boolean shim;

  /**
   * True to cache size calculation.
   */
  protected boolean cacheSizes = true;

  protected Size lastSize;
  /**
   * A specialized El that provides support for a shadow and shim. Will be
   * created if either {@link #shadow} or {@link #shim} is set to true.
   */
  protected Layer layer;

  protected String height;

  protected String width;

  private boolean shadow;
  private ShadowPosition shadowPosition = ShadowPosition.SIDES;
  private int shadowOffset = 4;

  private boolean deferHeight;
  private boolean autoHeight;
  private boolean autoWidth;
  private int left = Style.DEFAULT, top = Style.DEFAULT;
  private int pageX = Style.DEFAULT, pageY = Style.DEFAULT;
  private boolean boxReady;

  /**
   * Set this to true if you have sizing issues in initial collapsed or hidden
   * items. It defaults to false for performance reasons. You should not set
   * this to true for all components. If this is enabled than components are
   * made visible for the browser during a call to setSize if they were hidden
   * or collapsed. The user wont see this change. In the end of setSize the
   * status of the component is reverted again to the normal state. (defaults to
   * false)
   */
  protected boolean ensureVisibilityOnSizing;

  /**
   * Gets the current box measurements of the component's underlying element.
   * The component must be attached to return page coordinates.
   *
   * @param local if true the element's left and top are returned instead of
   *          page coordinates
   * @return the component's bounds
   */
  public Rectangle getBounds(boolean local) {
    return el().getBounds(local);
  }

  /**
   * Returns the component's offset height.
   *
   * @return the height
   */
  public int getHeight() {
    return el().getHeight();
  }

  /**
   * Return the component's height.
   *
   * @param content true to get the height minus borders and padding
   * @return the height
   */
  public int getHeight(boolean content) {
    return el().getHeight(content);
  }

  /**
   * Returns the component's current position. The component must be attached to
   * return page coordinates.
   *
   * @param local true to return the element's left and top rather than page
   *          coordinates
   * @return the position
   */
  public Point getPosition(boolean local) {
    if (local) {
      return new Point(el().getLeft(true), el().getTop(true));
    }
    return el().getXY();
  }

  /**
   * Returns true if the shadow is enabled.
   *
   * @return the shadow the shadow state
   */
  public boolean getShadow() {
    return shadow;
  }

  /**
   * Returns the shadow position.
   *
   * @return the shadow position
   */
  public ShadowPosition getShadowPosition() {
    return shadowPosition;
  }

  /**
   * Returns the shadow offset.
   *
   * @return the shadow offset
   */
  public int getShadowOffset() {
    return shadowOffset;
  }

  /**
   * Returns the component's size.
   *
   * @return the size
   */
  public Size getSize() {
    return el().getSize();
  }

  /**
   * Returns the component's width.
   *
   * @return the width
   */
  public int getWidth() {
    return getOffsetWidth();
  }

  /**
   * Returns the component's width.
   *
   * @param content true to get width minus borders and padding
   * @return the width
   */
  public int getWidth(boolean content) {
    return el().getWidth(content);
  }

  /**
   * @return the autoHeight
   */
  public boolean isAutoHeight() {
    return autoHeight;
  }

  /**
   * @return the autoWidth
   */
  public boolean isAutoWidth() {
    return autoWidth;
  }

  /**
   * Returns true if the height is being deferred
   *
   * @return the defer height state
   */
  public boolean isDeferHeight() {
    return deferHeight;
  }

  /**
   * Returns true if shimming is enabled.
   *
   * @return the shim state
   */
  public boolean isShim() {
    return shim;
  }

  /**
   * Sets the component's auto height value (defaults to false).
   *
   * @param autoHeight true to enable auto height
   */
  public void setAutoHeight(boolean autoHeight) {
    this.autoHeight = autoHeight;
  }

  /**
   * True to use width:'auto', false to use fixed width (defaults to false).
   *
   * @param autoWidth the auto width state
   */
  public void setAutoWidth(boolean autoWidth) {
    this.autoWidth = autoWidth;
  }

  /**
   * Sets the component's size. This method fires the <i>Move</i> and
   * <i>Resize</i> events. element.
   *
   * @param x the x coordinate
   * @param y the y coordinate
   * @param width the width
   * @param height the height
   */
  public void setBounds(int x, int y, int width, int height) {
    setPagePosition(x, y);
    setSize(width, height);
  }

  /**
   * Sets the component's size. This method fires the <i>Move</i> and
   * <i>Resize</i> events. element.
   *
   * @param bounds the update box
   */
  public void setBounds(Rectangle bounds) {
    setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
  }

  /**
   * True to defer height calculations to an external component, false to allow
   * this component to set its own height (defaults to false).
   *
   * @param deferHeight true to defer height
   */
  public void setDeferHeight(boolean deferHeight) {
    this.deferHeight = deferHeight;
  }

  /**
   * Sets the component's height. This method fires the <i>Resize</i> event.
   * element.
   *
   * @param height the new height
   */
  public void setHeight(int height) {
    setSize(-1, height);
  }

  /**
   * Sets the height of the component. This method fires the <i>Resize</i>
   * event. element.
   *
   * @param height the new height to set
   */
  public void setHeight(String height) {
    setSize(Style.UNDEFINED, height);
  }

  /**
   * Sets the page XY position of the component. To set the left and top
   * instead, use {@link #setPosition}. This method fires the <i>Move</i> event.
   *
   * @param x the x coordinate
   * @param y the y coordinate
   */
  public void setPagePosition(int x, int y) {
    if (x != Style.DEFAULT) {
      pageX = x;
    }
    if (y != Style.DEFAULT) {
      pageY = y;
    }
    if (!boxReady) {
      return;
    }
    Point p = getPositionEl().translatePoints(new Point(x, y));
    setPosition(p.x, p.y);
  }

  /**
   * Sets the page XY position of the component. To set the left and top
   * instead, use {@link #setPosition}. This method fires the <i>Move</i> event.
   *
   * @param point the new location
   */
  public void setPagePosition(Point point) {
    setPagePosition(point.x, point.y);
  }

  /**
   * Sets the width and height of the component. This method fires the resize
   * event.
   *
   * @param width the new width to set
   * @param height the new height to set
   */
  public void setPixelSize(int width, int height) {
    setSize(width, height);
  }

  /**
   * Sets the left and top of the component. To set the page XY position
   * instead, use {@link #setPagePosition}. This method fires the move event.
   *
   * @param left the new left
   * @param top the new top
   */
  public void setPosition(int left, int top) {
    this.left = left;
    this.top = top;

    if (!boxReady) {
      return;
    }

    Point p = new Point(left, top);

    p = adjustPosition(p);
    int ax = p.x, ay = p.y;

    El pel = getPositionEl();

    if (ax != Style.DEFAULT || ay != Style.DEFAULT) {
      if (ax != Style.DEFAULT && ay != Style.DEFAULT) {
        pel.setLeftTop(ax, ay);
      } else if (ax != Style.DEFAULT) {
        pel.setLeft(ax);
      } else if (ay != Style.DEFAULT) {
        pel.setTop(ay);
      }
      onPosition(ax, ay);

      if (GXT.isFocusManagerEnabled()) {
        FocusFrame.get().sync(this);
      }

      BoxComponentEvent be = (BoxComponentEvent) createComponentEvent(null);
      be.setX(ax);
      be.setY(ay);
      fireEvent(Events.Move, be);
    }
  }

  /**
   * True to enable a shadow that will be displayed behind the component
   * (defaults to false).
   *
   * @param shadow true to enable the shadow
   */
  public void setShadow(boolean shadow) {
    this.shadow = shadow;
  }

  /**
   * Sets the shadow position (defaults to SIDES).
   *
   * @param shadowPosition the position
   */
  public void setShadowPosition(ShadowPosition shadowPosition) {
    this.shadowPosition = shadowPosition;
    if (layer != null) {
      layer.setShadowPosition(shadowPosition);
    }
  }

  /**
   * Sets the shadow offset (defaults to 4).
   *
   * @param shadowOffset the offset
   */
  public void setShadowOffset(int shadowOffset) {
    this.shadowOffset = shadowOffset;
    setShadowPosition(shadowPosition);
  }

  /**
   * True to enable a shim which uses a transparent iframe to stop content from
   * bleeding through.
   *
   * @param shim true to enable a shim
   */
  public void setShim(boolean shim) {
    this.shim = shim;
  }

  /**
   * Sets the width and height of the component. This method fires the
   * <i>Resize</i> event.
   *
   * @param width the new width to set
   * @param height the new height to set
   */
  public void setSize(int width, int height) {
    if (!boxReady) {
      if (width != -1) {
        this.width = width + "px";
      }
      if (height != -1) {
        this.height = height + "px";
      }

      return;
    }

    Size size = new Size(width, height);
    if (cacheSizes && lastSize != null && lastSize.equals(size)) {
      return;
    }

    List<FastMap<Object>> list = makeVisible();

    lastSize = size;

    Size ads = adjustSize(size);

    int aw = ads.width;
    int ah = ads.height;

    if (autoWidth) {
      setStyleAttribute("width", "auto");
    }
    if (autoHeight) {
      setStyleAttribute("height", "auto");
    }

    if (!autoWidth && !autoHeight && !deferHeight) {
      el().setSize(aw, ah, adjustSize);
    } else if (!autoWidth) {
      el().setWidth(aw, adjustSize);
    } else if (!autoHeight && !deferHeight) {
      el().setHeight(ah, adjustSize);

    }

    onResize(aw, ah);

    sync(true);

    if (GXT.isFocusManagerEnabled()) {
      FocusFrame.get().sync(this);
    }

    restoreVisible(list);

    BoxComponentEvent ce = (BoxComponentEvent) createComponentEvent(null);
    ce.setWidth(aw);
    ce.setHeight(ah);
    fireEvent(Events.Resize, ce);
  }

  /**
   * Sets the width and height of the component. This method fires the
   * <i>Resize</i> event.
   *
   * @param width the new width to set
   * @param height the new height to set
   */
  public void setSize(String width, String height) {
    if (!boxReady) {
      if (width != null && !width.equals(Style.UNDEFINED)) {
        this.width = width;
      }
      if (height != null && !height.equals(Style.UNDEFINED)) {
        this.height = height;
      }
      return;
    }
    if (width == null) {
      width = Style.UNDEFINED;
    }
    if (height == null) {
      height = Style.UNDEFINED;
    }

    if (!width.equals(Style.UNDEFINED)) {
      width = El.addUnits(width, "px");
    }

    if (!height.equals(Style.UNDEFINED)) {
      height = El.addUnits(height, "px");
    }

    if ((height.equals(Style.UNDEFINED) && width.endsWith("px"))
        || (width.equals(Style.UNDEFINED) && height.endsWith("px")) || (width.endsWith("px") && height.endsWith("px"))) {
      setSize(Util.parseInt(width, Style.DEFAULT), Util.parseInt(height, Style.DEFAULT));
      return;
    }

    if (autoWidth) {
      el().setWidth("auto");
    } else if (!width.equals(Style.UNDEFINED)) {
      el().setWidth(width);
    }
    if (autoHeight) {
      el().setHeight("auto");
    } else if (!height.equals(Style.UNDEFINED)) {
      if (!deferHeight) {
        el().setHeight(height);
      }
    }

    int w = -1;
    int h = -1;

    List<FastMap<Object>> list = makeVisible();

    if (width.indexOf("px") != -1) {
      w = Integer.parseInt(width.substring(0, width.indexOf("px")));
    } else if (autoWidth || "auto".equals(width)) {
      w = -1;
    } else if (!width.equals(Style.UNDEFINED)) {
      w = getOffsetWidth();
    }

    if (height.indexOf("px") != -1) {
      h = Integer.parseInt(height.substring(0, height.indexOf("px")));
    } else if (autoHeight || "auto".equals(height)) {
      h = -1;
    } else if (!height.equals(Style.UNDEFINED)) {
      h = getOffsetHeight();
    }

    Size size = new Size(w, h);
    if (cacheSizes && lastSize != null && lastSize.equals(size)) {
      return;
    }

    lastSize = size;

    onResize(w, h);

    sync(true);

    if (GXT.isFocusManagerEnabled()) {
      FocusFrame.get().sync(this);
    }

    restoreVisible(list);

    BoxComponentEvent evt = (BoxComponentEvent) createComponentEvent(null);
    evt.setWidth(w);
    evt.setHeight(h);
    fireEvent(Events.Resize, evt);
  }

  /**
   * Sets the width of the component. This method fires the <i>Resize</i> event.
   *
   * @param width the new width to set
   */
  public void setWidth(int width) {
    setSize(width, -1);
  }

  /**
   * Sets the width of the component. This method fires the <i>Resize</i> event.
   *
   * @param width the new width to set
   */
  public void setWidth(String width) {
    setSize(width, Style.UNDEFINED);
  }

  /**
   * Syncs the layer of the component.
   */
  public void sync(boolean show) {
    if (layer != null) {
      layer.sync(show);
    }
  }

  /**
   * Clears the size cache and resets to the last known size.
   */
  public void syncSize() {
    Size oldSize = lastSize;
    lastSize = null;
    if (rendered && oldSize != null) {
      setSize(oldSize.width, oldSize.height);
    }
  }

  protected Point adjustPosition(Point point) {
    return point;
  }

  protected Size adjustSize(Size size) {
    return size;
  }

  @Override
  protected void afterRender() {
    super.afterRender();
    boxReady = true;

    if (shadow || (shim && GXT.useShims)) {
      layer = new Layer(getElement());
      if (shadow) {
        layer.enableShadow();
        layer.setShadowPosition(shadowPosition);
        layer.setShadowOffset(shadowOffset);
      }
      if (shim && GXT.useShims) {
        layer.enableShim();
      }
      setEl(layer);
    }

    if (width != null || height != null) {
      setSize(width, height);
    }

    if (left != Style.DEFAULT || top != Style.DEFAULT) {
      setPosition(left, top);
    }
    if (pageX != Style.DEFAULT || pageY != Style.DEFAULT) {
      setPagePosition(pageX, pageY);
    }
  }

  @Override
  protected ComponentEvent createComponentEvent(Event event) {
    BoxComponentEvent e = new BoxComponentEvent(this, event);
    return e;
  }

  /**
   * Returns the element to be used when positioning the component. Subclasses
   * may override as needed. Default method returns the component's root
   * element.
   *
   * @return the position element
   */
  protected El getPositionEl() {
    return el();
  }

  /**
   * Returns the element to be used when resizing the component. Subclasses may
   * override as needed. Default method returns the component's root element.
   *
   * @return the resize element
   */
  protected El getResizeEl() {
    return el();
  }

  protected void hideShadow() {
    if (layer != null) {
      layer.hideShadow();
    }
  }

  protected void hideShim() {
    if (layer != null) {
      layer.hideShim();
    }
  }

  protected void hideUnders() {
    if (layer != null) {
      layer.hideUnders();
    }
  }

  @Override
  protected void onHide() {
    super.onHide();
    hideUnders();
  }

  /**
   * Called after the component is moved, this method is empty by default but
   * can be implemented by any subclass that needs to perform custom logic after
   * a move occurs.
   *
   * @param x the new x position
   * @param y the new y position
   */
  protected void onPosition(int x, int y) {
  }

  /**
   * Called after the component is resized, this method is empty by default but
   * can be implemented by any subclass that needs to perform custom logic after
   * a resize occurs.
   *
   * @param width the width
   * @param height the height
   */
  protected void onResize(int width, int height) {
    if (mask) {
      mask(maskMessage, maskMessageStyleName);
    }
  }

  @Override
  protected void onShow() {
    super.onShow();
    sync(true);
  }

  @Override
  protected void onUnload() {
    super.onUnload();
    if (!hidden) {
      hideUnders();
    }
  }

  private List<FastMap<Object>> makeVisible() {
    if (ensureVisibilityOnSizing) {
      List<FastMap<Object>> list = new ArrayList<FastMap<Object>>();
      Element p = getElement();
      while (p != null && p != XDOM.getBody()) {
        if (fly(p).isStyleAttribute("display", "none")) {
          FastMap<Object> m = new FastMap<Object>();
          m.put("element", p);
          m.put("origd", p.getStyle().getProperty("display"));

          boolean hasxhideoffset = fly(p).hasStyleName("x-hide-offset");
          m.put("hasxhideoffset", hasxhideoffset);
          if (!hasxhideoffset) {
            fly(p).addStyleName("x-hide-offset");
          }
          p.getStyle().setProperty("display", "block");
          list.add(m);
        }
        p = (Element) p.getParentElement();
      }
      return list;
    }
    return null;
  }

  private void restoreVisible(List<FastMap<Object>> list) {
    if (ensureVisibilityOnSizing && list != null) {
      for (FastMap<Object> m : list) {
        Element e = (Element) m.get("element");
        e.getStyle().setProperty("display", (String) m.get("origd"));
        if (!((Boolean) m.get("hasxhideoffset")).booleanValue()) {
          fly(e).removeStyleName("x-hide-offset");
        }
      }
    }
  }
}
TOP

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

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.