com.sencha.gxt.widget.core.client.CollapsePanel.java Source code

Java tutorial

Introduction

Here is the source code for com.sencha.gxt.widget.core.client.CollapsePanel.java

Source

/**
 * Sencha GXT 4.0.0 - Sencha for GWT
 * Copyright (c) 2006-2015, Sencha Inc.
 *
 * licensing@sencha.com
 * http://www.sencha.com/products/gxt/license/
 *
 * ================================================================================
 * Open Source License
 * ================================================================================
 * This version of Sencha GXT is licensed under the terms of the Open Source GPL v3
 * license. You may use this license only if you are prepared to distribute and
 * share the source code of your application under the GPL v3 license:
 * http://www.gnu.org/licenses/gpl.html
 *
 * If you are NOT prepared to distribute and share the source code of your
 * application under the GPL v3 license, other commercial and oem licenses
 * are available for an alternate download of Sencha GXT.
 *
 * Please see the Sencha GXT Licensing page at:
 * http://www.sencha.com/products/gxt/license/
 *
 * For clarification or additional options, please contact:
 * licensing@sencha.com
 * ================================================================================
 *
 *
 * ================================================================================
 * Disclaimer
 * ================================================================================
 * THIS SOFTWARE IS DISTRIBUTED "AS-IS" WITHOUT ANY WARRANTIES, CONDITIONS AND
 * REPRESENTATIONS WHETHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
 * IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, MERCHANTABLE QUALITY,
 * FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, NON-INFRINGEMENT, PERFORMANCE AND
 * THOSE ARISING BY STATUTE OR FROM CUSTOM OR USAGE OF TRADE OR COURSE OF DEALING.
 * ================================================================================
 */
package com.sencha.gxt.widget.core.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Display;
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.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.core.client.Style.Anchor;
import com.sencha.gxt.core.client.Style.AnchorAlignment;
import com.sencha.gxt.core.client.Style.Direction;
import com.sencha.gxt.core.client.Style.LayoutRegion;
import com.sencha.gxt.core.client.dom.CompositeElement;
import com.sencha.gxt.core.client.dom.XDOM;
import com.sencha.gxt.core.client.dom.XElement;
import com.sencha.gxt.core.client.gestures.TapGestureRecognizer;
import com.sencha.gxt.core.client.util.BaseEventPreview;
import com.sencha.gxt.fx.client.FxElement;
import com.sencha.gxt.fx.client.animation.AfterAnimateEvent;
import com.sencha.gxt.fx.client.animation.AfterAnimateEvent.AfterAnimateHandler;
import com.sencha.gxt.fx.client.animation.Fx;
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.container.BorderLayoutContainer.BorderLayoutData;
import com.sencha.gxt.widget.core.client.event.ExpandEvent;
import com.sencha.gxt.widget.core.client.event.ExpandEvent.ExpandHandler;
import com.sencha.gxt.widget.core.client.event.ExpandEvent.HasExpandHandlers;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.event.SelectEvent.SelectHandler;

/**
 * Acts as a stand-in for a collapsed {@link ContentPanel}. Used by
 * {@link com.sencha.gxt.widget.core.client.container.BorderLayoutContainer}.
 */
public class CollapsePanel extends Component implements HasExpandHandlers {

    /**
     * Provides the appearance of a {@link CollapsePanel}.
     */
    public interface CollapsePanelAppearance {
        /**
         * Renders the {@link CollapsePanel} appearance for the given region into
         * safe HTML.
         *
         * @param sb receives the rendered appearance
         * @param region the region
         * @param header true to include header text
         */
        public void render(SafeHtmlBuilder sb, LayoutRegion region, boolean header);

        /**
         * Returns the element that wraps the icon for the {@link CollapsePanel}.
         * 
         * @param parent the parent of the icon wrapper (generally
         *          {@link #getElement}).
         * @return the icon wrapper
         */
        XElement iconWrap(XElement parent);

        /**
         * Returns the element that wraps the text for the {@link CollapsePanel}.
         *
         * @param parent the parent of the text wrapper (generally
         *          {@link #getElement}).
         * @return the text wrapper
         */
        XElement textWrap(XElement parent);
    }

    private ContentPanel panel;
    private LayoutRegion region;
    private ToolButton expandBtn;
    private boolean expanded;
    private final CollapsePanelAppearance appearance;
    private boolean animate = false;
    private boolean disableAnimations;
    private BorderLayoutData panelData;
    private BaseEventPreview preview;

    /**
     * Creates a {@link CollapsePanel} that acts as a stand-in for the given panel
     * when it is collapsed.
     * 
     * @param panel the content panel
     * @param data layout data describing a region in a border panel
     * @param region the region this panel occupies in the border panel
     */
    public CollapsePanel(ContentPanel panel, BorderLayoutData data, LayoutRegion region) {
        this(GWT.<CollapsePanelAppearance>create(CollapsePanelAppearance.class), panel, data, region);
    }

    /**
     * Creates a {@link CollapsePanel} that acts as a stand-in for the given panel
     * when it is collapsed.
     * 
     * @param appearance the appearance instance to use when rendering and updating the dom
     * @param panel the content panel
     * @param data layout data describing a region in a border panel
     * @param region the region this panel occupies in the border panel
     */
    public CollapsePanel(CollapsePanelAppearance appearance, ContentPanel panel, BorderLayoutData data,
            LayoutRegion region) {
        this.panel = panel;
        this.panelData = data;
        this.region = region;
        this.appearance = appearance;
        monitorWindowResize = true;

        SafeHtmlBuilder builder = new SafeHtmlBuilder();
        this.appearance.render(builder, region, data.isCollapseHeaderVisible());

        setElement((Element) XDOM.create(builder.toSafeHtml()));
        sinkEvents(Event.ONCLICK);

        IconConfig config = ToolButton.DOUBLERIGHT;
        switch (region) {
        case EAST:
            config = ToolButton.DOUBLELEFT;
            break;
        case NORTH:
            config = ToolButton.DOUBLEDOWN;
            break;
        case SOUTH:
            config = ToolButton.DOUBLEUP;
            break;
        default:
            // do nothing
        }

        expandBtn = new ToolButton(config);
        expandBtn.addSelectHandler(new SelectHandler() {

            @Override
            public void onSelect(SelectEvent event) {
                if (expanded) {
                    disableAnimations = false;
                    collapse();
                    disableAnimations = true;
                }
                onExpandButton();
            }
        });

        appearance.iconWrap(getElement()).appendChild(expandBtn.getElement());
        appearance.textWrap(getElement()).setInnerSafeHtml(panel.getHeading());
    }

    @Override
    public HandlerRegistration addExpandHandler(ExpandHandler handler) {
        return addHandler(handler, ExpandEvent.getType());
    }

    /**
     * Collapses an expanded {@link CollapsePanel}, optionally animating it so
     * that it appears to collapse toward the direction of its associated region.
     * Has no effect if the panel is not expanded.
     */
    public void collapse() {
        if (expanded) {
            if (animate) {
                Fx fx = new Fx();
                fx.addAfterAnimateHandler(new AfterAnimateHandler() {
                    @Override
                    public void onAfterAnimate(AfterAnimateEvent event) {
                        afterCollapse();
                    }
                });
                Direction d = Direction.LEFT;
                switch (region) {
                case EAST:
                    d = Direction.RIGHT;
                    break;
                case SOUTH:
                    d = Direction.DOWN;
                    break;
                case NORTH:
                    d = Direction.UP;
                    break;
                default:
                    // do nothing
                }

                panel.getElement().<FxElement>cast().slideOut(d, fx);
            } else {
                afterCollapse();
            }
        }
    }

    private SplitBar splitBar;

    private SplitBar createSplitBar(LayoutRegion region) {
        switch (region) {
        case WEST:
            return new SplitBar(LayoutRegion.EAST, this);
        case EAST:
            return new SplitBar(LayoutRegion.WEST, this);
        case NORTH:
            return new SplitBar(LayoutRegion.SOUTH, this);
        case SOUTH:
            return new SplitBar(LayoutRegion.NORTH, this);
        case CENTER:
            // do nothing
        }

        return null;
    }

    /**
     * Returns the split bar, creating it if necessary. Shows a mini-collapse tool
     * in the split bar if the collapse panel was created with
     * {@link BorderLayoutData#isCollapseMini()} true.
     * 
     * @return the split bar
     */
    public SplitBar getSplitBar() {
        if (splitBar == null) {
            splitBar = createSplitBar(region);
            splitBar.disableDragging();
            if (panelData.isCollapseMini()) {
                splitBar.setCollapsible(true);
                switch (region) {
                case EAST:
                    splitBar.updateMini(Direction.LEFT);
                    break;
                case WEST:
                    splitBar.updateMini(Direction.RIGHT);
                    break;
                case NORTH:
                    splitBar.updateMini(Direction.DOWN);
                    break;
                case SOUTH:
                    splitBar.updateMini(Direction.UP);
                    break;
                case CENTER:
                    // do nothing
                }
            }
        }

        return splitBar;
    }

    /**
     * Collapses a {@link CollapsePanel} so that it is hidden.
     */
    public void collapseHidden() {
        XElement wrap = appearance.iconWrap(getElement());
        if (wrap != null) {
            wrap.removeChildren();
        }

        getElement().getStyle().setProperty("border", "none");

        SplitBar bar = getData("splitBar");
        if (bar != null) {
            switch (region) {
            case EAST:
                bar.setXOffset(bar.getHandleWidth());
                break;
            case WEST:
                bar.setXOffset(-bar.getHandleWidth());
                break;
            case NORTH:
                bar.setYOffset(-bar.getHandleWidth());
                break;
            case SOUTH:
                bar.setYOffset(bar.getHandleWidth());
                break;
            case CENTER:
                // do nothing
            }

            bar.disableDragging();
        }
    }

    /**
     * Expands a collapsed {@link CollapsePanel}, optionally animating it so that
     * it appears to expand from the direction of its associated region. Has no
     * effect if the panel is not collapsed.
     */
    public void expand() {
        if (panelData.isFloatable() && !expanded) {
            SplitBar bar = panel.getData("splitBar");
            if (bar != null) {
                bar.getElement().getStyle().setDisplay(Display.NONE);
            }

            for (Widget w : panel.getHeader().getTools()) {
                w.getElement().getStyle().setVisibility(Visibility.HIDDEN);
            }
            panel.getElement().updateZIndex(0);
            panel.getElement().setVisible(true);
            RootPanel.get().add(panel);

            SplitBar collapseBar = getData("splitBar");
            if (bar != null) {
                collapseBar.getElement().getStyle().setDisplay(Display.NONE);
            }

            Direction d = Direction.RIGHT;
            AnchorAlignment align = new AnchorAlignment(Anchor.TOP_LEFT, Anchor.TOP_RIGHT);
            switch (region) {
            case EAST:
                d = Direction.LEFT;
                align = new AnchorAlignment(Anchor.TOP_RIGHT, Anchor.TOP_LEFT);
                break;
            case SOUTH:
                align = new AnchorAlignment(Anchor.BOTTOM_LEFT, Anchor.TOP_LEFT);
                d = Direction.UP;
                break;
            case NORTH:
                d = Direction.DOWN;
                align = new AnchorAlignment(Anchor.TOP_LEFT, Anchor.BOTTOM_LEFT);
                break;
            case WEST:
            case CENTER:
                // do nothing
            }
            panel.getElement().alignTo(getElement(), align, 0, 0);

            if (animate && !disableAnimations) {
                Fx fx = new Fx();
                fx.addAfterAnimateHandler(new AfterAnimateHandler() {
                    @Override
                    public void onAfterAnimate(AfterAnimateEvent event) {
                        expanded = true;
                    }
                });
                panel.getElement().<FxElement>cast().slideIn(d, fx);
            } else {
                expanded = true;
            }

            final TapGestureRecognizer previewTapGestureRecognizer = new TapGestureRecognizer() {
                @Override
                public boolean handleEnd(NativeEvent endEvent) {
                    super.handleEnd(endEvent);
                    XElement target = endEvent.getEventTarget().cast();
                    if (!panel.getElement().isOrHasChild(target) && !(getElement().isOrHasChild(target))) {
                        collapse();
                        return false;
                    }
                    return true;
                }
            };

            preview = new BaseEventPreview() {
                @Override
                protected boolean onPreview(NativePreviewEvent pe) {
                    switch (pe.getTypeInt()) {
                    case Event.ONCLICK:
                    case Event.ONMOUSEDOWN:
                        XElement target = pe.getNativeEvent().getEventTarget().cast();
                        if (!panel.getElement().isOrHasChild(target) && !(getElement().isOrHasChild(target))) {
                            collapse();
                            remove();
                        }

                        break;
                    case Event.ONTOUCHSTART:
                    case Event.ONTOUCHMOVE:
                    case Event.ONTOUCHCANCEL:
                        previewTapGestureRecognizer.handle(pe.getNativeEvent());
                        break;
                    case Event.ONTOUCHEND:
                        if (!previewTapGestureRecognizer.handle(pe.getNativeEvent())) {
                            remove();
                        }
                    }
                    return true;
                }
            };
            CompositeElement comp = new CompositeElement();
            comp.add(panel.getElement());
            preview.setIgnoreList(comp);
            preview.add();
        }
    }

    public CollapsePanelAppearance getAppearance() {
        return appearance;
    }

    /**
     * Returns the {@link ContentPanel} associated with this {@link CollapsePanel}
     * .
     * 
     * @return the content panel
     */
    public ContentPanel getContentPanel() {
        return panel;
    }

    /**
     * Returns the {@link LayoutRegion} associated with this {@link CollapsePanel}
     * .
     * 
     * @return the layout region
     */
    public LayoutRegion getRegion() {
        return region;
    }

    @Override
    public void onBrowserEvent(Event event) {
        super.onBrowserEvent(event);

        if (event.getTypeInt() == Event.ONCLICK) {
            event.stopPropagation();
            XElement target = event.getEventTarget().cast();
            if (expandBtn.getElement().isOrHasChild(target)) {
                disableAnimations = false;
                collapse();
                disableAnimations = true;
                onExpandButton();
            } else {
                onBarClick(event);
            }
        }

    }

    @Override
    protected void onWindowResize(int width, int height) {
        if (expanded) {
            if (preview != null) {
                preview.remove();
            }
            collapse();
        }
    }

    public void setIconConfig(IconConfig config) {
        expandBtn.changeStyle(config);
    }

    /**
     * Displays the collapsed form of the {@link CollapsePanel}
     */
    protected void afterCollapse() {
        RootPanel.get().remove(panel);
        SplitBar bar = panel.getData("splitBar");
        if (bar != null) {
            bar.getElement().getStyle().setDisplay(Display.BLOCK);
        }

        SplitBar collapseBar = getData("splitBar");
        if (collapseBar != null) {
            collapseBar.getElement().getStyle().setDisplay(Display.BLOCK);
        }

        for (Widget w : panel.getHeader().getTools()) {
            w.getElement().getStyle().setVisibility(Visibility.VISIBLE);
        }
        panel.getElement().getStyle().setDisplay(Display.BLOCK);
        expanded = false;
    }

    @Override
    protected void doAttachChildren() {
        super.doAttachChildren();
        ComponentHelper.doAttach(expandBtn);
    }

    @Override
    protected void doDetachChildren() {
        super.doDetachChildren();
        ComponentHelper.doDetach(expandBtn);
    }

    protected void onBarClick(Event event) {
        if (!expanded) {
            expand();
        } else {
            collapse();
        }
    }

    protected void onExpandButton() {

    }

}