ch.takoyaki.email.html.client.ui.generic.ScrolledTabLayoutPanel.java Source code

Java tutorial

Introduction

Here is the source code for ch.takoyaki.email.html.client.ui.generic.ScrolledTabLayoutPanel.java

Source

/*******************************************************************************
 * Copyright (c) 2013 takoyaki.ch.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     takoyaki.ch - Initial version
 ******************************************************************************/
// http://devnotesblog.wordpress.com/2010/06/17/scrollable-gwt-tablayoutpanel/
package ch.takoyaki.email.html.client.ui.generic;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.TabLayoutPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * A {@link TabLayoutPanel} that shows scroll buttons if necessary
 */
public class ScrolledTabLayoutPanel extends TabLayoutPanel {

    private static final int IMAGE_PADDING_PIXELS = 4;

    private LayoutPanel panel;
    private FlowPanel tabBar;
    private Image scrollLeftButton;
    private Image scrollRightButton;
    private HandlerRegistration windowResizeHandler;

    private ImageResource leftArrowImage;
    private ImageResource rightArrowImage;

    /**
     * @param barHeight
     *            the size of the tab bar
     * @param barUnit
     *            the unit in which the tab bar size is specified
     * @param leftArrowImage
     *            the scroll left image
     * @param rihgArrowImage
     *            the scroll right image
     */
    public ScrolledTabLayoutPanel(double barHeight, Unit barUnit, ImageResource leftArrowImage,
            ImageResource rightArrowImage) {
        super(barHeight, barUnit);

        this.leftArrowImage = leftArrowImage;
        this.rightArrowImage = rightArrowImage;

        // The main widget wrapped by this composite, which is a LayoutPanel
        // with the tab bar & the tab content
        panel = (LayoutPanel) getWidget();

        // Find the tab bar, which is the first flow panel in the LayoutPanel
        for (int i = 0; i < panel.getWidgetCount(); ++i) {
            Widget widget = panel.getWidget(i);
            if (widget instanceof FlowPanel) {
                tabBar = (FlowPanel) widget;
                break; // tab bar found
            }
        }

        initScrollButtons();
    }

    @Override
    public void add(Widget child, Widget tab) {
        super.add(child, tab);
        checkIfScrollButtonsNecessary();
    }

    @Override
    public boolean remove(int index) {
        boolean b = super.remove(index);
        checkIfScrollButtonsNecessary();
        return b;
    }

    @Override
    public boolean remove(Widget w) {
        boolean b = super.remove(w);
        checkIfScrollButtonsNecessary();
        return b;
    }

    @Override
    protected void onLoad() {
        super.onLoad();

        if (windowResizeHandler == null) {
            windowResizeHandler = Window.addResizeHandler(new ResizeHandler() {
                @Override
                public void onResize(ResizeEvent event) {
                    checkIfScrollButtonsNecessary();
                }
            });
        }
    }

    @Override
    protected void onUnload() {
        super.onUnload();

        if (windowResizeHandler != null) {
            windowResizeHandler.removeHandler();
            windowResizeHandler = null;
        }
    }

    private ClickHandler createScrollClickHandler(final int diff) {
        return new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                Widget lastTab = getLastTab();
                if (lastTab == null)
                    return;

                int newLeft = parsePosition(tabBar.getElement().getStyle().getLeft()) + diff;
                int rightOfLastTab = getRightOfWidget(lastTab);

                // Prevent scrolling the last tab too far away form the right
                // border,
                // or the first tab further than the left border position

                newLeft = Math.max(getTabBarWidth() - rightOfLastTab - 20, newLeft);
                newLeft = Math.min(0, newLeft);
                if (newLeft <= 0) {
                    scrollTo(newLeft);
                }
            }
        };
    }

    private void indentTabbar(boolean indent) {
        Element container = tabBar.getElement().getParentElement();
        container.addClassName("scroll_tabs");
        if (indent) {
            container.addClassName("scroll");
        } else {
            container.removeClassName("scroll");
        }
    }

    private void setScrollVisible(boolean visible) {
        indentTabbar(visible);
        panel.setWidgetVisible(scrollRightButton, visible);
        panel.setWidgetVisible(scrollLeftButton, visible);
    }

    /** Create and attach the scroll button images with a click handler */
    private void initScrollButtons() {
        scrollLeftButton = new Image(leftArrowImage);
        int leftImageWidth = scrollLeftButton.getWidth();

        panel.insert(scrollLeftButton, 0);
        panel.getWidgetContainerElement(scrollLeftButton).addClassName("left_scroll");

        panel.setWidgetLeftWidth(scrollLeftButton, 0, Unit.PX, leftImageWidth, Unit.PX);
        panel.setWidgetTopHeight(scrollLeftButton, 0, Unit.PX, scrollLeftButton.getWidth(), Unit.PX);
        scrollLeftButton.addClickHandler(createScrollClickHandler(+80));

        scrollRightButton = new Image(rightArrowImage);
        panel.insert(scrollRightButton, 0);
        panel.getWidgetContainerElement(scrollRightButton).addClassName("right_scroll");
        panel.setWidgetLeftWidth(scrollRightButton, leftImageWidth + IMAGE_PADDING_PIXELS, Unit.PX,
                scrollRightButton.getWidth(), Unit.PX);
        panel.setWidgetTopHeight(scrollRightButton, 0, Unit.PX, scrollRightButton.getHeight(), Unit.PX);

        scrollRightButton.addClickHandler(createScrollClickHandler(-80));

        setScrollVisible(false);
    }

    private void checkIfScrollButtonsNecessary() {
        // Defer size calculations until sizes are available, when calculating
        // immediately after
        // add(), all size methods return zero
        Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {

            @Override
            public void execute() {
                boolean isScrolling = isScrollingNecessary();
                // When the scroll buttons are being hidden, reset the scroll
                // position to zero to
                // make sure no tabs are still out of sight
                if (scrollRightButton.isVisible() && !isScrolling) {
                    resetScrollPosition();
                }
                setScrollVisible(isScrolling);
            }

        });

    }

    private void resetScrollPosition() {
        scrollTo(0);
    }

    private void scrollTo(int pos) {
        tabBar.getElement().getStyle().setLeft(pos, Unit.PX);
    }

    private boolean isScrollingNecessary() {
        Widget lastTab = getLastTab();
        if (lastTab == null)
            return false;

        return getRightOfWidget(lastTab) > getTabBarWidth();
    }

    private int getRightOfWidget(Widget widget) {
        return widget.getElement().getOffsetLeft() + widget.getElement().getOffsetWidth();
    }

    private int getTabBarWidth() {
        //return tabBar.getElement().getParentElement().getClientWidth();
        return tabBar.getElement().getParentElement().getOffsetWidth();
    }

    private Widget getLastTab() {
        if (tabBar.getWidgetCount() == 0)
            return null;

        return tabBar.getWidget(tabBar.getWidgetCount() - 1);
    }

    private static int parsePosition(String positionString) {
        int position;
        try {
            for (int i = 0; i < positionString.length(); i++) {
                char c = positionString.charAt(i);
                if (c != '-' && !(c >= '0' && c <= '9')) {
                    positionString = positionString.substring(0, i);
                }
            }

            position = Integer.parseInt(positionString);
        } catch (NumberFormatException ex) {
            position = 0;
        }
        return position;
    }
}