Package com.sencha.gxt.widget.core.client.container

Source Code of com.sencha.gxt.widget.core.client.container.BorderLayoutContainer

/**
* Sencha GXT 3.1.0-beta - Sencha for GWT
* Copyright(c) 2007-2014, Sencha, Inc.
* licensing@sencha.com
*
* http://www.sencha.com/products/gxt/license/
*/
package com.sencha.gxt.widget.core.client.container;

import java.util.logging.Logger;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.uibinder.client.UiChild;
import com.google.gwt.uibinder.client.UiConstructor;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.core.client.GXTLogConfiguration;
import com.sencha.gxt.core.client.Style.Direction;
import com.sencha.gxt.core.client.Style.LayoutRegion;
import com.sencha.gxt.core.client.Style.Side;
import com.sencha.gxt.core.client.dom.XDOM;
import com.sencha.gxt.core.client.dom.XElement;
import com.sencha.gxt.core.client.resources.CommonStyles;
import com.sencha.gxt.core.client.util.Margins;
import com.sencha.gxt.core.client.util.Rectangle;
import com.sencha.gxt.core.client.util.Size;
import com.sencha.gxt.widget.core.client.CollapsePanel;
import com.sencha.gxt.widget.core.client.Collapsible;
import com.sencha.gxt.widget.core.client.Component;
import com.sencha.gxt.widget.core.client.ContentPanel;
import com.sencha.gxt.widget.core.client.SplitBar;
import com.sencha.gxt.widget.core.client.button.IconButton.IconConfig;
import com.sencha.gxt.widget.core.client.button.ToolButton;
import com.sencha.gxt.widget.core.client.event.BeforeCollapseEvent;
import com.sencha.gxt.widget.core.client.event.BeforeCollapseEvent.BeforeCollapseHandler;
import com.sencha.gxt.widget.core.client.event.BeforeExpandEvent;
import com.sencha.gxt.widget.core.client.event.BeforeExpandEvent.BeforeExpandHandler;
import com.sencha.gxt.widget.core.client.event.CollapseItemEvent;
import com.sencha.gxt.widget.core.client.event.CollapseItemEvent.CollapseItemHandler;
import com.sencha.gxt.widget.core.client.event.CollapseItemEvent.HasCollapseItemHandlers;
import com.sencha.gxt.widget.core.client.event.ExpandItemEvent;
import com.sencha.gxt.widget.core.client.event.ExpandItemEvent.ExpandItemHandler;
import com.sencha.gxt.widget.core.client.event.ExpandItemEvent.HasExpandItemHandlers;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.event.SelectEvent.SelectHandler;
import com.sencha.gxt.widget.core.client.event.SplitBarDragEvent;
import com.sencha.gxt.widget.core.client.event.SplitBarDragEvent.SplitBarDragHandler;

/**
* A multi-pane, application-oriented layout container that supports multiple regions, automatic split bars between
* regions and built-in expanding and collapsing of regions.
* <p/>
* Region positions are specified using compass points (e.g. north for top, west for left, east for right, south for
* bottom) and center. The center region is a privileged position that receives the remaining space not allocated to
* other regions. Border layout containers should generally specify a center region and one or more other regions.
* <p/>
* Region layout parameters are specified using {@link BorderLayoutData} which controls the margin between the regions,
* the size of the region, the minimum and maximum size, whether the region has a split bar, whether the region is
* collapsible and other details.
* <p/>
* Region size may be specified as a percent of the parent container size or a fixed number of pixels. The region size
* is specified as a single value that describes the orientation associated with the region (height for north and south,
* width for west and east).
* <p/>
* The size, split bar and collapsible attributes are specified in the <code>BorderLayoutData</code> for the region
* adjacent to the center region.
* <p />
* Code Snippet:
*
* <pre>
    BorderLayoutContainer con = new BorderLayoutContainer();

    ContentPanel cp = new ContentPanel();
    cp.setHeadingText("North");
    cp.add(new Label("North Content"));
    BorderLayoutData d = new BorderLayoutData(.20);
    d.setMargins(new Margins(5));
    d.setCollapsible(true);
    d.setSplit(true);
    con.setNorthWidget(cp, d);

    cp = new ContentPanel();
    cp.setHeadingText("West");
    cp.add(new Label("West Content"));
    d = new BorderLayoutData(.20);
    d.setMargins(new Margins(0, 5, 5, 5));
    d.setCollapsible(true);
    d.setSplit(true);
    d.setCollapseMini(true);
    con.setWestWidget(cp, d);

    cp = new ContentPanel();
    cp.setHeadingText("Center");
    cp.add(new Label("Center Content"));
    d = new BorderLayoutData();
    d.setMargins(new Margins(0, 5, 5, 0));
    con.setCenterWidget(cp, d);

    Viewport v = new Viewport();
    v.add(con);
    RootPanel.get().add(v);
* </pre>
*/
public class BorderLayoutContainer extends SimpleContainer implements HasCenterWidget, HasNorthWidget, HasSouthWidget,
    HasEastWidget, HasWestWidget, HasCollapseItemHandlers<ContentPanel>, HasExpandItemHandlers<ContentPanel> {

  @SuppressWarnings("javadoc")
  public interface BorderLayoutAppearance {
    XElement getContainerTarget(XElement parent);

    void onInsert(Widget child);

    void onRemove(Widget child);

    void render(SafeHtmlBuilder sb);
  }

  /**
   * Specifies region layout parameters which control the margin between the regions, the size of the region, the
   * minimum and maximum size, whether the region has a split bar, whether the region is collapsible and other details.
   * The size, split bar and collapsible attributes are specified in the <code>BorderLayoutData</code> for the region
   * adjacent to the center region. The center region is allocated the remaining space.
   */
  public static class BorderLayoutData extends MarginData implements HasSize, LayoutData {

    private double size = 100;
    private boolean split;
    private boolean hidden;
    private int minSize = 50;
    private int maxSize = 500;
    private boolean collapsible;
    private boolean collapseMini;
    private boolean collapseHidden;
    private boolean floatable = true;
    private boolean collapsed;

    /**
     * Creates a border layout data with default values for <code>size</code> (100), <code>minSize</code> (50) and
     * <code>maxSize</code> (500).
     */
    public BorderLayoutData() {

    }

    /**
     * Creates a border layout data with default values for <code>minSize</code> (50) and <code>maxSize</code> (500) and
     * the specified value for size.
     *
     * @param size the region size (height for north and south, width for west and east)
     */
    @UiConstructor
    public BorderLayoutData(double size) {
      setSize(size);
    }

    /**
     * Returns the region's maximum size.
     *
     * @return the maximum size
     */
    public int getMaxSize() {
      return maxSize;
    }

    /**
     * Returns the region's minimum size.
     *
     * @return the minimum size
     */
    public int getMinSize() {
      return minSize;
    }

    @Override
    public double getSize() {
      return size;
    }

    /**
     * Returns the collapsed state
     *
     * @return the collapsed state
     */
    public boolean isCollapsed() {
      return collapsed;
    }

    /**
     * Returns true if the collapse panel is hidden.
     *
     * @return the collapse hidden state
     */
    public boolean isCollapseHidden() {
      return collapseHidden;
    }

    /**
     * Returns true if the mini split bar collapse tool is enabled.
     *
     * @return true if the mini split bar collapse tool is enabled
     */
    public boolean isCollapseMini() {
      return collapseMini;
    }

    /**
     * Returns true if collapsing is enabled.
     *
     * @return the collapse state
     */
    public boolean isCollapsible() {
      return collapsible;
    }

    /**
     * Returns true if the region is floatable.
     *
     * @return the float state
     */
    public boolean isFloatable() {
      return floatable;
    }

    /**
     * Returns true if the component is hidden.
     *
     * @return the hidden state
     */
    public boolean isHidden() {
      return hidden;
    }

    /**
     * Returns true if the region is split.
     *
     * @return the split state
     */
    public boolean isSplit() {
      return split;
    }

    /**
     * Sets the collapsed state.
     *
     * @param collapsed true to render collapsed
     */
    public void setCollapsed(boolean collapsed) {
      this.collapsed = collapsed;
    }

    /**
     * True to hide the collapse panel when a region is collapsed (defaults to false).
     *
     * @param collapseHidden the collapse hidden state
     */
    public void setCollapseHidden(boolean collapseHidden) {
      this.collapseHidden = collapseHidden;
    }

    /**
     * True to add a mini-collapase tool in the split bar. Enabling will make the region resizable.
     *
     * @param collapseMini true to add tool
     */
    public void setCollapseMini(boolean collapseMini) {
      this.collapseMini = collapseMini;
      this.split = true;
    }

    /**
     * True to allow the user to collapse this region (defaults to false). If true, an expand/collapse tool button will
     * automatically be rendered into the title bar of the region, otherwise the button will not be shown.
     *
     * @param collapsible true to enable collapsing
     */
    public void setCollapsible(boolean collapsible) {
      this.collapsible = collapsible;
    }

    /**
     * True to allow clicking a collapsed region's bar to display the region's panel floated above the layout, false to
     * force the user to fully expand a collapsed region by clicking the expand button to see it again (defaults to
     * true).
     *
     * @param floatable true to enable floating
     */
    public void setFloatable(boolean floatable) {
      this.floatable = floatable;
    }

    /**
     * True to hide the component.
     *
     * @param hidden true to hide
     */
    public void setHidden(boolean hidden) {
      this.hidden = hidden;
    }

    /**
     * Sets the maximum allowable size in pixels for this region (defaults to 500).
     *
     * @param maxSize the max size
     */
    public void setMaxSize(int maxSize) {
      this.maxSize = maxSize;
    }

    /**
     * Sets the minimum allowable size in pixels for this region (defaults to 50).
     *
     * @param minSize the min size
     */
    public void setMinSize(int minSize) {
      this.minSize = minSize;
    }

    @Override
    public void setSize(double size) {
      this.size = size;
    }

    /**
     * True to display a {@link SplitBar} between this region and its neighbor, allowing the user to resize the regions
     * dynamically (defaults to false). When split = true, it is common to specify a {@link #minSize} and
     * {@link #maxSize} for the region.
     *
     * @param split true to enable a split bar
     */
    public void setSplit(boolean split) {
      this.split = split;
    }
  }

  private class Handler implements BeforeCollapseHandler, BeforeExpandHandler {
    @Override
    public void onBeforeCollapse(BeforeCollapseEvent event) {
      event.setCancelled(true);
      onCollapse((ContentPanel) event.getSource());

    }

    @Override
    public void onBeforeExpand(BeforeExpandEvent event) {
      event.setCancelled(true);
      onExpand((ContentPanel) event.getSource());
    }

  }

  protected Widget east;
  protected Widget north;
  protected Widget south;
  protected Widget west;

  private Handler collapseHandler = new Handler();
  private Rectangle lastCenter;
  private final BorderLayoutAppearance appearance;

  private static Logger logger = Logger.getLogger(BorderLayoutContainer.class.getName());

  /**
   * Creates a border layout container with the default appearance.
   */
  public BorderLayoutContainer() {
    this(GWT.<BorderLayoutAppearance> create(BorderLayoutAppearance.class));
  }

  /**
   * Creates a border layout container with the specified appearance.
   *
   * @param appearance the appearance of the border layout container
   */
  public BorderLayoutContainer(BorderLayoutAppearance appearance) {
    super(true);
    this.appearance = appearance;

    SafeHtmlBuilder builder = new SafeHtmlBuilder();
    this.appearance.render(builder);

    setElement((Element) XDOM.create(builder.toSafeHtml()));

    getElement().makePositionable();
  }

  @Override
  public HandlerRegistration addCollapseHandler(CollapseItemHandler<ContentPanel> handler) {
    return addHandler(handler, CollapseItemEvent.getType());
  }

  @Override
  public HandlerRegistration addExpandHandler(ExpandItemHandler<ContentPanel> handler) {
    return addHandler(handler, ExpandItemEvent.getType());
  }

  /**
   * Collapses the panel in the given region. If the target widget is hidden no action will be performed.
   *
   * @param region the region to be collapsed
   */
  public void collapse(LayoutRegion region) {
    Widget w = getRegionWidget(region);
    if (w != null && w instanceof ContentPanel && !(w instanceof CollapsePanel)) {
      BorderLayoutData data = getLayoutData(w);
      if (data.isHidden()) {
        return;
      }
      onCollapse((ContentPanel) w);
    }
  }

  /**
   * Expands the panel in the given region. If the target widget is hidden no action will be performed.
   *
   * @param region the region to expand
   */
  public void expand(LayoutRegion region) {
    Widget w = getRegionWidget(region);
    if (w != null && w instanceof CollapsePanel) {
      BorderLayoutData data = getLayoutData(w);
      if (data.isHidden()) {
        return;
      }
      CollapsePanel collapse = (CollapsePanel) w;
      ContentPanel cp = (ContentPanel) collapse.getData("panel");
      onExpand(cp);
    }
  }

  public BorderLayoutAppearance getAppearance() {
    return appearance;
  }

  @Override
  public Widget getCenterWidget() {
    return getWidget();
  }

  @Override
  public Widget getEastWidget() {
    return east;
  }

  @Override
  public Widget getNorthWidget() {
    return north;
  }

  /**
   * Returns the widget in the specified region, or null if there is no widget for that region.
   *
   * @param region the region
   * @return the widget in the specified region, or null if there is no widget for that region
   */
  public Widget getRegionWidget(LayoutRegion region) {
    switch (region) {
      case CENTER:
        return getCenterWidget();
      case NORTH:
        return getNorthWidget();
      case EAST:
        return getEastWidget();
      case SOUTH:
        return getSouthWidget();
      case WEST:
        return getWestWidget();
    }
    return null;
  }

  @Override
  public Widget getSouthWidget() {
    return south;
  }

  @Override
  public Widget getWestWidget() {
    return west;
  }

  /**
   * Hides the component in the given region.
   *
   * @param region the layout region
   */
  public void hide(LayoutRegion region) {
    Widget c = getRegionWidget(region);
    if (c != null) {
      BorderLayoutData data = (BorderLayoutData) c.getLayoutData();
      data.setHidden(true);
      doLayout();
    }
  }

  @Override
  public void setCenterWidget(IsWidget child) {
    setWidget(child);
  }

  /**
   * Sets the widget in the center region of the border layout container. The center region is a privileged position
   * that receives the remaining space not allocated to other regions. Border layout containers should generally specify
   * a center region and one or more other regions.
   *
   * @param child the widget to put in the center region
   * @param layoutData the layout data for the widget
   */
  @UiChild(limit = 1, tagname = "center")
  public void setCenterWidget(IsWidget child, MarginData layoutData) {
    if (child != null) {
      child.asWidget().setLayoutData(layoutData);
    }
    setCenterWidget(child);
  }

  @Override
  public void setEastWidget(IsWidget child) {
    if (east != null) {
      remove(east);
    }
    if (child != null) {
      east = child.asWidget();
      insert(east, 0);

    }
  }

  /**
   * Sets the widget in the east (right) region of the border layout container.
   * <p>
   * <ul>
   * <li>In order to use layoutData.setCollapsible(true) the child has to be a {@link ContentPanel}
   * <li>When using layoutData.setSplit(true) the child can implement {@link Collapsible}.
   * When the child implements collapsible, on selection of the split, it will collapse the child.
   * </ul>
   *
   * @param child the widget to put in the east region
   * @param layoutData the layout data for the widget
   */
  @UiChild(limit = 1, tagname = "east")
  public void setEastWidget(IsWidget child, BorderLayoutData layoutData) {
    assertLayoutDataFeaturesUsed("setEastWidget", child, layoutData);
    if (child != null) {
      child.asWidget().setLayoutData(layoutData);
    }
    setEastWidget(child);
  }

  @Override
  public void setNorthWidget(IsWidget child) {
    if (north != null) {
      remove(north);
    }
    if (child != null) {
      north = child.asWidget();

      insert(north, 0);
    }
  }

  /**
   * Sets the widget in the north (top) region of the border layout container.
   * <p>
   * <ul>
   * <li>In order to use layoutData.setCollapsible(true) the child has to be a {@link ContentPanel}
   * <li>When using layoutData.setSplit(true) the child can implement {@link Collapsible}.
   * When the child implements collapsible, on selection of the split, it will collapse the child.
   * </ul>
   *
   * @param child the widget to put in the north region
   * @param layoutData the layout data for the widget
   */
  @UiChild(limit = 1, tagname = "north")
  public void setNorthWidget(IsWidget child, BorderLayoutData layoutData) {
    assertLayoutDataFeaturesUsed("setNorthWidget", child, layoutData);
    if (child != null) {
      child.asWidget().setLayoutData(layoutData);
    }
    setNorthWidget(child);
  }

  @Override
  public void setSouthWidget(IsWidget child) {
    if (south != null) {
      remove(south);
    }
    if (child != null) {
      south = child.asWidget();
      insert(south, 0);
    }
  }

  /**
   * Sets the widget in the south (bottom) region of the border layout container.
   * <p>
   * <ul>
   * <li>In order to use layoutData.setCollapsible(true) the child has to be a {@link ContentPanel}
   * <li>When using layoutData.setSplit(true) the child can implement {@link Collapsible}.
   * When the child implements collapsible, on selection of the split, it will collapse the child.
   * </ul>
   *
   * @param child the widget to put in the south region
   * @param layoutData the layout data for the widget
   */
  @UiChild(limit = 1, tagname = "south")
  public void setSouthWidget(IsWidget child, BorderLayoutData layoutData) {
    assertLayoutDataFeaturesUsed("setSouthWidget", child, layoutData);
    if (child != null) {
      child.asWidget().setLayoutData(layoutData);
    }
    setSouthWidget(child);
  }

  @Override
  public void setWestWidget(IsWidget child) {
    if (west != null) {
      remove(west);
    }
    if (child != null) {
      west = child.asWidget();
      insert(west, 0);
    }
  }

  /**
   * Sets the widget in the west (left) region of the border layout container.
   * <p>
   * <ul>
   * <li>In order to use layoutData.setCollapsible(true) the child has to be a {@link ContentPanel}
   * <li>When using layoutData.setSplit(true) the child can implement {@link Collapsible}.
   * When the child implements collapsible, on selection of the split, it will collapse the child.
   * </ul>
   *
   * @param child the widget to put in the west region
   * @param layoutData the layout data for the widget
   */
  @UiChild(limit = 1, tagname = "west")
  public void setWestWidget(IsWidget child, BorderLayoutData layoutData) {
    assertLayoutDataFeaturesUsed("setWestWidget", child, layoutData);
    if (child != null) {
      child.asWidget().setLayoutData(layoutData);
    }
    setWestWidget(child);
  }

  /**
   * Shows the component in the given region.
   *
   * @param region the layout region
   */
  public void show(LayoutRegion region) {
    Widget c = getRegionWidget(region);
    if (c != null) {
      BorderLayoutData data = (BorderLayoutData) c.getLayoutData();
      data.setHidden(false);
      doLayout();
    }
  }

  @Override
  protected void applyLayout(Widget component, Rectangle box) {
    super.applyLayout(component, box);
    if (component instanceof Component) {
      final SplitBar bar = ((Component) component).getData("splitBar");
      if (bar != null) {
        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
          @Override
          public void execute() {
            bar.getElement().getStyle().setVisibility(Visibility.VISIBLE);
          }
        });
      }
    }
  }

  protected CollapsePanel createCollapsePanel(ContentPanel panel, BorderLayoutData data, LayoutRegion region) {
    return new CollapsePanel(panel, data, region) {
      protected void onExpandButton() {
        super.onExpandButton();
        onExpandClick(this);
      }
    };
  }

  protected SplitBar createSplitBar(Component component) {
    if (component == north) {
      return new SplitBar(LayoutRegion.SOUTH, component);
    } else if (component == south) {
      return new SplitBar(LayoutRegion.NORTH, component);
    } else if (component == west) {
      return new SplitBar(LayoutRegion.EAST, component);
    } else if (component == east) {
      return new SplitBar(LayoutRegion.WEST, component);
    }
    return null;
  }

  @Override
  protected void doLayout() {
    for (int i = 0; i < getWidgetCount(); i++) {
      Widget w = getWidget(i);
      if (w instanceof ContentPanel && w.getLayoutData() instanceof BorderLayoutData) {
        BorderLayoutData data = (BorderLayoutData) w.getLayoutData();
        if (getRegion((Component) w) != LayoutRegion.CENTER) {
          if (data.isCollapsed()) {
            switchPanels((ContentPanel) w);
          }
        }
      }
    }

    Size size = getContainerTarget().getStyleSize();

    if (GXTLogConfiguration.loggingIsEnabled()) {
      logger.finest(getId() + " doLayout size: " + size);
    }

    int w = size.getWidth();
    int h = size.getHeight();

    int sLeft = getContainerTarget().getPadding(Side.LEFT);
    int sTop = getContainerTarget().getPadding(Side.TOP);
    int centerW = w, centerH = h, centerY = 0, centerX = 0;

    if (north != null) {
      BorderLayoutData data = getLayoutData(north);
      north.setVisible(!data.isHidden());

      if (north.isVisible()) {
        Rectangle b = new Rectangle();
        Margins m = data.getMargins() != null ? data.getMargins() : new Margins();
        double s = data.getSize() <= 1 ? data.getSize() * size.getHeight() : data.getSize();
        b.setHeight((int) s);
        b.setWidth(w - (m.getLeft() + m.getRight()));
        b.setX(m.getLeft());
        b.setY(m.getTop());
        centerY = b.getHeight() + b.getY() + m.getBottom();
        centerH -= centerY;
        b.setX(b.getX() + sLeft);
        b.setY(b.getY() + sTop);
        applyLayout(north, b);
      }
    }
    if (south != null) {
      BorderLayoutData data = getLayoutData(south);
      south.setVisible(!data.isHidden());
      if (south.isVisible()) {
        Rectangle b = new Rectangle();
        Margins m = data.getMargins() != null ? data.getMargins() : new Margins();
        double s = data.getSize() <= 1 ? data.getSize() * size.getHeight() : data.getSize();
        b.setHeight((int) s);
        b.setWidth(w - (m.getLeft() + m.getRight()));
        b.setX(m.getLeft());
        int totalHeight = (b.getHeight() + m.getTop() + m.getBottom());
        b.setY(h - totalHeight + m.getTop());
        centerH -= totalHeight;
        b.setX(b.getX() + sLeft);
        b.setY(b.getY() + sTop);
        applyLayout(south, b);
      }
    }

    if (west != null) {
      BorderLayoutData data = getLayoutData(west);
      west.setVisible(!data.isHidden());
      if (west.isVisible()) {
        Rectangle box = new Rectangle();
        Margins m = data.getMargins() != null ? data.getMargins() : new Margins();
        double s = data.getSize() <= 1 ? data.getSize() * size.getWidth() : data.getSize();
        box.setWidth((int) s);
        box.setHeight(centerH - (m.getTop() + m.getBottom()));
        box.setX(m.getLeft());
        box.setY(centerY + m.getTop());
        int totalWidth = (box.getWidth() + m.getLeft() + m.getRight());
        centerX += totalWidth;
        centerW -= totalWidth;
        box.setX(box.getX() + sLeft);
        box.setY(box.getY() + sTop);
        applyLayout(west, box);
      }

    }
    if (east != null) {
      BorderLayoutData data = getLayoutData(east);
      east.setVisible(!data.isHidden());
      if (east.isVisible()) {
        Rectangle b = new Rectangle();
        Margins m = data.getMargins() != null ? data.getMargins() : new Margins();
        double s = data.getSize() <= 1 ? data.getSize() * size.getWidth() : data.getSize();
        b.setWidth((int) s);
        b.setHeight(centerH - (m.getTop() + m.getBottom()));
        int totalWidth = (b.getWidth() + m.getLeft() + m.getRight());
        b.setX(w - totalWidth + m.getLeft());
        b.setY(centerY + m.getTop());
        centerW -= totalWidth;
        b.setX(b.getX() + sLeft);
        b.setY(b.getY() + sTop);
        applyLayout(east, b);
      }
    }

    if (widget != null) {
      Object data = widget.getLayoutData();
      Margins m = null;
      if (data instanceof HasMargins) {
        m = ((HasMargins) data).getMargins();
      }
      if (m == null) {
        m = new Margins(0);
      }
      lastCenter = new Rectangle(centerX, centerY, centerW, centerH);
      lastCenter.setX(centerX + (m.getLeft() + sLeft));
      lastCenter.setY(centerY + (m.getTop() + sTop));
      lastCenter.setWidth(centerW - (m.getLeft() + m.getRight()));
      lastCenter.setHeight(centerH - (m.getTop() + m.getBottom()));
      applyLayout(widget, lastCenter);
    }
  }

  @Override
  protected XElement getContainerTarget() {
    return appearance.getContainerTarget(getElement());
  }

  protected LayoutRegion getRegion(Component component) {
    if (component == north) {
      return LayoutRegion.NORTH;
    } else if (component == south) {
      return LayoutRegion.SOUTH;
    } else if (component == west) {
      return LayoutRegion.WEST;
    } else if (component == east) {
      return LayoutRegion.EAST;
    }

    return null;
  }

  protected void onCollapse(ContentPanel panel) {
    switchPanels(panel);

    doLayout();

    CollapsePanel cp = (CollapsePanel) panel.getData("collapse");
    SplitBar bar = cp.getSplitBar();
    if (bar != null) {
      bar.sync();
    }

    fireEvent(new CollapseItemEvent<ContentPanel>(panel));
  }

  protected void onExpand(ContentPanel panel) {
    CollapsePanel cp = panel.getData("collapse");

    LayoutRegion region = getRegion(cp);

    switch (region) {
      case WEST:
        setWestWidget(panel);
        break;
      case EAST:
        setEastWidget(panel);
        break;
      case NORTH:
        setNorthWidget(panel);
        break;
      case SOUTH:
        setSouthWidget(panel);
        break;
      case CENTER:
        // do nothing
        break;
    }

    setCollapsed(panel, false);

    BorderLayoutData data = (BorderLayoutData) panel.getLayoutData();
    data.setCollapsed(false);

    doLayout();

    fireEvent(new ExpandItemEvent<ContentPanel>(panel));
  }

  protected void onExpandClick(CollapsePanel collapse) {
    ContentPanel panel = collapse.getContentPanel();
    onExpand(panel);
  }


  @Override
  protected void onInsert(int index, Widget child) {
    child.addStyleName(CommonStyles.get().positionable());

    appearance.onInsert(child);

    if (!(child instanceof Component)) {
      return;
    }

    final Component c = (Component) child;

    if (c == getWidget()) {
      return;
    }

    final BorderLayoutData data = getLayoutData(c);

    if (c instanceof CollapsePanel) {
      final CollapsePanel collapse = (CollapsePanel) c;
      final BorderLayoutData panelData = (BorderLayoutData) collapse.getContentPanel().getLayoutData();
      SplitBar bar = collapse.getData("splitBar");
      if (bar == null || bar.getTargetWidget() != c) {
        bar = collapse.getSplitBar();
        bar.setCollapsible(panelData.isCollapseMini());

        c.setData("splitBar", bar);

        if (panelData.isCollapseHidden()) {
          collapse.collapseHidden();
        }

        bar.addSelectHandler(new SelectHandler() {
          @Override
          public void onSelect(SelectEvent event) {
            onExpandClick((CollapsePanel) c);
          }
        });
      }
    }

    if (data.isCollapsible() && c instanceof ContentPanel && !c.isRendered()) {
      final ContentPanel cp = (ContentPanel) c;
      cp.setCollapsible(true);
      cp.setHideCollapseTool(true);

      IconConfig config = ToolButton.DOUBLELEFT;

      switch (getRegion(cp)) {
        case NORTH:
          config = ToolButton.DOUBLEUP;
          break;
        case SOUTH:
          config = ToolButton.DOUBLEDOWN;
          break;
        case EAST:
          config = ToolButton.DOUBLERIGHT;
          break;
        case WEST:
        case CENTER:
          // do nothing
      }

      cp.getHeader().addTool(new ToolButton(config, new SelectHandler() {

        @Override
        public void onSelect(SelectEvent event) {
          cp.collapse();
        }
      }));
      cp.addBeforeCollapseHandler(collapseHandler);
      cp.addBeforeExpandHandler(collapseHandler);
    }

    if (data.isSplit()) {
      SplitBar bar = c.getData("splitBar");
      if (bar == null || bar.getTargetWidget() != c) {
        bar = createSplitBar(c);
        final SplitBar fbar = bar;
        bar.setCollapsible(data.isCollapseMini());
        if (data.isCollapseMini()) {
          switch (getRegion(c)) {
            case EAST:
              bar.updateMini(Direction.RIGHT);
              break;
            case WEST:
              bar.updateMini(Direction.LEFT);
              break;
            case NORTH:
              bar.updateMini(Direction.UP);
              break;
            case SOUTH:
              bar.updateMini(Direction.DOWN);
              break;
            case CENTER:
              // do nothing
          }
          bar.addSelectHandler(new SelectHandler() {
            @Override
            public void onSelect(SelectEvent event) {
              if (c instanceof Collapsible) {
                ((Collapsible) c).collapse();
              }
            }
          });
        }

        bar.addSplitBarDragHandler(new SplitBarDragHandler() {

          @Override
          public void onDragEvent(SplitBarDragEvent event) {
            LayoutRegion region = getRegion(c);
            if (event.isStart()) {
              boolean side = region == LayoutRegion.WEST || region == LayoutRegion.EAST;
              int size = side ? c.getOffsetWidth() : c.getOffsetHeight();
              int centerSize = side ? lastCenter.getWidth() : lastCenter.getHeight();

              fbar.setMinSize(data.getMinSize());
              fbar.setMaxSize(Math.min(size + centerSize, data.getMaxSize()));

            } else {
              if (event.getSize() < 1) {
                return;
              }
              data.setSize(event.getSize());
              doLayout();
            }
          }
        });

      }
      bar.getElement().getStyle().setVisibility(Visibility.HIDDEN);
      c.setData("splitBar", bar);

      bar.setMinSize(data.getMinSize());
      bar.setMaxSize(data.getMaxSize() == 0 ? bar.getMaxSize() : data.getMaxSize());
      bar.setAutoSize(false);
    }
  }

  @Override
  protected void onRemove(Widget child) {
    super.onRemove(child);

    appearance.onRemove(child);

    if (north == child) {
      north = null;
    } else if (south == child) {
      south = null;
    } else if (east == child) {
      east = null;
    } else if (west == child) {
      west = null;
    }
    child.removeStyleName(CommonStyles.get().positionable());
  }

  private BorderLayoutData getLayoutData(Widget w) {
    Object o = w.getLayoutData();
    return (BorderLayoutData) ((o instanceof BorderLayoutData) ? o : new BorderLayoutData(100));
  }

  private native void setCollapsed(ContentPanel panel, boolean collapse) /*-{
    panel.@com.sencha.gxt.widget.core.client.ContentPanel::collapsed = collapse;
  }-*/;

  private void switchPanels(ContentPanel panel) {
    LayoutRegion region = getRegion(panel);

    BorderLayoutData data = (BorderLayoutData) getLayoutData(panel);
    remove(panel);

    CollapsePanel cp = (CollapsePanel) panel.getData("collapse");
    if (cp == null) {
      cp = createCollapsePanel(panel, data, region);

      BorderLayoutData collapseData = new BorderLayoutData();
      collapseData.setSize(data.isCollapseHidden() ? 0 : 24);

      Margins m = data.getMargins();
      if (m == null) {
        m = new Margins();
        data.setMargins(m);
      }
      collapseData.setMargins(new Margins(m.getTop(), m.getRight(), m.getBottom(), m.getLeft()));

      if (data.isCollapseHidden()) {
        cp.collapseHidden();
        collapseData.setSize(0);
        switch (region) {
          case WEST:
            collapseData.getMargins().setLeft(0);
            break;
          case EAST:
            collapseData.getMargins().setRight(0);
            break;
          case NORTH:
            collapseData.getMargins().setTop(0);
            break;
          case SOUTH:
            collapseData.getMargins().setBottom(0);
            break;
          case CENTER:
            // do nothing
        }
      }

      cp.setLayoutData(collapseData);
      cp.setData("panel", panel);
      panel.setData("collapse", cp);
    }

    cp.clearSizeCache();

    setCollapsed(panel, true);

    switch (region) {
      case WEST:
        setWestWidget(cp);
        break;
      case EAST:
        setEastWidget(cp);
        break;
      case NORTH:
        setNorthWidget(cp);
        break;
      case SOUTH:
        setSouthWidget(cp);
        break;
      case CENTER:
        // do nothing
    }
  }

  private void assertLayoutDataFeaturesUsed(String from, IsWidget child, BorderLayoutData layoutData) {
    assert !layoutData.isCollapsible() || child instanceof ContentPanel : "In order to use layoutData.setCollapsible(true) " + from + "(child, layoutData) a GXT ContentPanel has to be used as the child widget.";
  }

}
TOP

Related Classes of com.sencha.gxt.widget.core.client.container.BorderLayoutContainer

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.