com.google.gwt.user.client.ui.ScrollPanel.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.user.client.ui.ScrollPanel.java

Source

/*
 * Copyright 2008 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.user.client.ui;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.touch.client.TouchScroller;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;

/**
 * A simple panel that wraps its contents in a scrollable area.
 */
@SuppressWarnings("deprecation")
public class ScrollPanel extends SimplePanel
        implements SourcesScrollEvents, RequiresResize, ProvidesResize, HasScrolling {
    private final Element containerElem;

    private final Element scrollableElem;

    /**
     * The scroller used to support touch events.
     */
    private TouchScroller touchScroller;

    /**
     * Creates an empty scroll panel.
     */
    public ScrollPanel() {
        this.scrollableElem = getElement();
        scrollableElem.ensureId();
        this.containerElem = Document.get().createDivElement();
        containerElem.ensureId();
        scrollableElem.appendChild(containerElem);
        initialize();
    }

    /**
     * Creates a new scroll panel with the given child widget.
     * 
     * @param child
     *            the widget to be wrapped by the scroll panel
     */
    public ScrollPanel(Widget child) {
        this();
        setWidget(child);
    }

    /**
     * Creates an empty scroll panel using the specified root, scrollable, and
     * container elements.
     * 
     * @param root
     *            the root element of the Widget
     * @param scrollable
     *            the scrollable element, which can be the same as the root
     *            element
     * @param container
     *            the container element that holds the child
     */
    protected ScrollPanel(Element root, Element scrollable, Element container) {
        super(root);
        this.scrollableElem = scrollable;
        this.containerElem = container;
        initialize();
    }

    @Override
    public HandlerRegistration addScrollHandler(ScrollHandler handler) {
        /*
         * Sink the event on the scrollable element, which may not be the root
         * element.
         */
        Event.sinkEvents(getScrollableElement(), Event.getEventsSunk(getScrollableElement()) | Event.ONSCROLL);
        return addHandler(handler, ScrollEvent.getType());
    }

    /**
     * @deprecated Use {@link #addScrollHandler} instead
     */
    @Override
    @Deprecated
    public void addScrollListener(ScrollListener listener) {
        ListenerWrapper.WrappedScrollListener.add(this, listener);
    }

    /**
     * Ensures that the specified item is visible, by adjusting the panel's
     * scroll position.
     * 
     * @param item
     *            the item whose visibility is to be ensured
     */
    public void ensureVisible(UIObject item) {
        Element scroll = getScrollableElement();
        Element element = item.getElement();
        ensureVisibleImpl(scroll, element);
    }

    /**
     * Gets the horizontal scroll position.
     * 
     * @return the horizontal scroll position, in pixels
     */
    @Override
    public int getHorizontalScrollPosition() {
        return getScrollableElement().getScrollLeft();
    }

    @Override
    public int getMaximumHorizontalScrollPosition() {
        return ScrollImpl.get().getMaximumHorizontalScrollPosition(getScrollableElement());
    }

    @Override
    public int getMaximumVerticalScrollPosition() {
        return getScrollableElement().getScrollHeight() - getScrollableElement().getClientHeight();
    }

    @Override
    public int getMinimumHorizontalScrollPosition() {
        return ScrollImpl.get().getMinimumHorizontalScrollPosition(getScrollableElement());
    }

    @Override
    public int getMinimumVerticalScrollPosition() {
        return 0;
    }

    /**
     * Gets the vertical scroll position.
     * 
     * @return the vertical scroll position, in pixels
     * @deprecated as of GWT 2.3, replaced by
     *             {@link #getVerticalScrollPosition()}
     */
    @Deprecated
    public int getScrollPosition() {
        return getScrollableElement().getScrollTop();
    }

    @Override
    public int getVerticalScrollPosition() {
        return getScrollPosition();
    }

    /**
     * Check whether or not touch based scrolling is disabled. This method
     * always returns false on devices that do not support touch scrolling.
     * 
     * @return true if disabled, false if enabled
     */
    public boolean isTouchScrollingDisabled() {
        return touchScroller == null;
    }

    @Override
    public void onResize() {
        Widget child = getWidget();
        if ((child != null) && (child instanceof RequiresResize)) {
            ((RequiresResize) child).onResize();
        }
    }

    /**
     * @deprecated Use the {@link HandlerRegistration#removeHandler} method on
     *             the object returned by {@link #addScrollHandler} instead
     */
    @Override
    @Deprecated
    public void removeScrollListener(ScrollListener listener) {
        ListenerWrapper.WrappedScrollListener.remove(this, listener);
    }

    /**
     * Scroll to the bottom of this panel.
     */
    public void scrollToBottom() {
        setVerticalScrollPosition(getMaximumVerticalScrollPosition());
    }

    /**
     * Scroll to the far left of this panel.
     */
    public void scrollToLeft() {
        setHorizontalScrollPosition(getMinimumHorizontalScrollPosition());
    }

    /**
     * Scroll to the far right of this panel.
     */
    public void scrollToRight() {
        setHorizontalScrollPosition(getMaximumHorizontalScrollPosition());
    }

    /**
     * Scroll to the top of this panel.
     */
    public void scrollToTop() {
        setVerticalScrollPosition(getMinimumVerticalScrollPosition());
    }

    /**
     * Sets whether this panel always shows its scroll bars, or only when
     * necessary.
     * 
     * @param alwaysShow
     *            <code>true</code> to show scroll bars at all times
     */
    public void setAlwaysShowScrollBars(boolean alwaysShow) {
        getScrollableElement().getStyle().setOverflow(alwaysShow ? Overflow.SCROLL : Overflow.AUTO);
    }

    /**
     * Sets the object's height. This height does not include decorations such
     * as border, margin, and padding.
     * 
     * @param height
     *            the object's new height, in absolute CSS units (e.g. "10px",
     *            "1em" but not "50%")
     */
    @Override
    public void setHeight(String height) {
        super.setHeight(height);
    }

    /**
     * Sets the horizontal scroll position.
     * 
     * @param position
     *            the new horizontal scroll position, in pixels
     */
    @Override
    public void setHorizontalScrollPosition(int position) {
        getScrollableElement().setScrollLeft(position);
    }

    /**
     * Sets the vertical scroll position.
     * 
     * @param position
     *            the new vertical scroll position, in pixels
     * @deprecated as of GWT 2.3, replaced by
     *             {@link #setVerticalScrollPosition(int)}
     */
    @Deprecated
    public void setScrollPosition(int position) {
        getScrollableElement().setScrollTop(position);
    }

    /**
     * Sets the object's size. This size does not include decorations such as
     * border, margin, and padding.
     * 
     * @param width
     *            the object's new width, in absolute CSS units (e.g. "10px",
     *            "1em", but not "50%")
     * @param height
     *            the object's new height, in absolute CSS units (e.g. "10px",
     *            "1em", but not "50%")
     */
    @Override
    public void setSize(String width, String height) {
        super.setSize(width, height);
    }

    /**
     * Set whether or not touch scrolling is disabled. By default, touch
     * scrolling is enabled on devices that support touch events.
     * 
     * @param isDisabled
     *            true to disable, false to enable
     * @return true if touch scrolling is enabled and supported, false if
     *         disabled or not supported
     */
    public boolean setTouchScrollingDisabled(boolean isDisabled) {
        if (isDisabled == isTouchScrollingDisabled()) {
            return isDisabled;
        }
        if (isDisabled) {
            // Detach the touch scroller.
            touchScroller.setTargetWidget(null);
            touchScroller = null;
        } else {
            // Attach a new touch scroller.
            touchScroller = TouchScroller.createIfSupported(this);
        }
        return isTouchScrollingDisabled();
    }

    @Override
    public void setVerticalScrollPosition(int position) {
        setScrollPosition(position);
    }

    /**
     * Sets the object's width. This width does not include decorations such as
     * border, margin, and padding.
     * 
     * @param width
     *            the object's new width, in absolute CSS units (e.g. "10px",
     *            "1em", but not "50%")
     */
    @Override
    public void setWidth(String width) {
        super.setWidth(width);
    }

    private native void ensureVisibleImpl(Element scroll, Element e) /*-{
                                                                     if (!e)
                                                                     return; 
                                                                         
                                                                     var item = e;
                                                                     var realOffset = 0;
                                                                     while (item && (item != scroll)) {
                                                                     realOffset += item.offsetTop;
                                                                     item = item.offsetParent;
                                                                     }
                                                                         
                                                                     scroll.scrollTop = realOffset - scroll.offsetHeight / 2;
                                                                     }-*/;

    /**
     * Initialize the widget.
     */
    private void initialize() {
        setAlwaysShowScrollBars(false);
        // Prevent IE standard mode bug when a AbsolutePanel is contained.
        scrollableElem.getStyle().setPosition(Position.RELATIVE);
        containerElem.getStyle().setPosition(Position.RELATIVE);
        // Hack to account for the IE6/7 scrolling bug described here:
        // http://stackoverflow.com/questions/139000/div-with-overflowauto-and-a-100-wide-table-problem
        scrollableElem.getStyle().setProperty("zoom", "1");
        containerElem.getStyle().setProperty("zoom", "1");
        // Enable touch scrolling.
        setTouchScrollingDisabled(false);
        // Initialize the scrollable element.
        // FIXME - localdom2 - this gives edge-case resolution issues
        Scheduler.get().scheduleFinally(() -> {
            scrollableElem.implAccess().ensureRemote();
            containerElem.implAccess().ensureRemote();
            ScrollImpl.get().initialize(scrollableElem, containerElem);
        });
    }

    @Override
    protected Element getContainerElement() {
        return DOM.asOld(containerElem);
    }

    /**
     * Get the scrollable element. That is the element with its overflow set to
     * 'auto' or 'scroll'.
     * 
     * @return the scrollable element
     */
    protected Element getScrollableElement() {
        return DOM.asOld(scrollableElem);
    }

    @Override
    protected void onAttach() {
        super.onAttach();
        /*
         * Attach the event listener in onAttach instead of onLoad so users
         * cannot accidentally override it. If the scrollable element is the
         * same as the root element, then we set the event listener twice (once
         * in super.onAttach() and once here), which is fine.
         */
        Event.setEventListener(getScrollableElement(), this);
    }

    @Override
    protected void onDetach() {
        /*
         * Detach the event listener in onDetach instead of onUnload so users
         * cannot accidentally override it.
         */
        Event.setEventListener(getScrollableElement(), null);
        super.onDetach();
    }
}