org.gwtlib.client.table.ui.PagingBar.java Source code

Java tutorial

Introduction

Here is the source code for org.gwtlib.client.table.ui.PagingBar.java

Source

/*
 * Copyright 2008 Sander Berents
 *
 * 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 org.gwtlib.client.table.ui;

import org.gwtlib.client.ui.Messages;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

/**
 * Paging bar.
 * 
 * CSS Style Rules:
 * <ul>
 * <li>.gwtlib-PagingBar { the paging bar itself }</li>
 * <li>.gwtlib-PagingBar-position { current position section }</li>
 * <li>.gwtlib-PagingBar-browser { browser secion }</li>
 * <li>.gwtlib-PagingBar-goto { go to page selection section }</li>
 * <li>.gwtlib-PagingBar-gotoButton { go to button of page selection section }</li>
 * <li>.gwtlib-PagingBar-gotoButton-up { go to button of page selection section }</li>
 * <li>.gwtlib-PagingBar-gotoButton-up-disabled { go to button of page selection section in disabled state }</li>
 * <li>.gwtlib-PagingBar-pagesize { page size section }</li>
 * <li>.gwtlib-PagingBar-browser-first { first page button }</li>
 * <li>.gwtlib-PagingBar-browser-first-up { first page button in enabled state }</li>
 * <li>.gwtlib-PagingBar-browser-first-up-disabled { first page button in disabled state }</li>
 * <li>.gwtlib-PagingBar-browser-prev { previous page button }</li>
 * <li>.gwtlib-PagingBar-browser-prev-up { previous page button in enabled state }</li>
 * <li>.gwtlib-PagingBar-browser-prev-up-disabled { previous page button in disabled state }</li>
 * <li>.gwtlib-PagingBar-browser-next { next page button }</li>
 * <li>.gwtlib-PagingBar-browser-next-up { next page button in enabled state }</li>
 * <li>.gwtlib-PagingBar-browser-next-up-disabled { next page button in disabled state }</li>
 * <li>.gwtlib-PagingBar-browser-last { last page button }</li>
 * <li>.gwtlib-PagingBar-browser-last-up { last page button in enabled state }</li>
 * <li>.gwtlib-PagingBar-browser-last-up-disabled { last page button in disabled state }</li>
 * <li>.gwtlib-PagingBar-browser-page { currently selected page }</li>
 * <li>.gwtlib-PagingBar-browser-page-enabled { other selectable page }</li>
 * <li>.gwtlib-PagingBar-loading { data loading status }</li>
 * <li>.gwtlib-PagingBar-loading-up { data loading status }</li>
 * <li>.gwtlib-PagingBar-loading-up-disabled { data loading status (finished loading) }</li>
 * </ul>
 * 
 * @author Sander Berents
 */
public class PagingBar extends Composite implements HasValueChangeHandlers<Integer> {
    private static final String STYLE = "gwtlib-PagingBar";
    private static final String STYLE_POSITION = "gwtlib-PagingBar-position";
    private static final String STYLE_BROWSER = "gwtlib-PagingBar-browser";
    private static final String STYLE_GOTO = "gwtlib-PagingBar-goto";
    private static final String STYLE_GOTO_BUTTON = "gwtlib-PagingBar-gotoButton";
    private static final String STYLE_PAGESIZE = "gwtlib-PagingBar-pagesize";
    private static final String STYLE_PAGE = "gwtlib-PagingBar-browser-page";
    private static final String STYLE_LOADING = "gwtlib-PagingBar-loading";
    private static final String STYLE_ENABLED = "enabled";

    private static final String[] STYLES_BROWSER = { "gwtlib-PagingBar-browser-first",
            "gwtlib-PagingBar-browser-prev", "gwtlib-PagingBar-browser-next", "gwtlib-PagingBar-browser-last" };

    private static final int FIRST = 0;
    private static final int PREV = 1;
    private static final int NEXT = 2;
    private static final int LAST = 3;

    private static final int DEFAULT_LIMIT = 60000;

    private int _page; // Zero based current page
    private int _size; // Total number of results
    private int _limit = DEFAULT_LIMIT;
    private int _pageSize;
    private int[] _pageSizes;
    private int _pages; // Number of pages, computed from size/limit/pageSize
    private boolean _loading;

    private Widget _positionWidget;
    private Widget _loadingWidget;
    private Widget _browserWidget;
    private Widget _gotoWidget;
    private Widget _pageSizesWidget;
    protected Messages _messages = (Messages) GWT.create(Messages.class);

    public PagingBar(int size, int pageSize) {
        this(0, size, pageSize, null);
    }

    @Deprecated
    public PagingBar(Messages messages, int size, int pageSize) {
        this(0, size, pageSize, null);
        _messages = messages;
    }

    public PagingBar(int page, int size, int pageSize, int[] pageSizes) {
        _page = page;
        _size = size;
        _pageSize = pageSize;
        _pageSizes = pageSizes;
        _pages = computeNumPages();

        // Create widgets in protected methods to provide customization hooks
        _positionWidget = createPositionWidget();
        if (_positionWidget != null)
            updatePositionWidget(_positionWidget);
        _loadingWidget = createLoadingWidget();
        if (_loadingWidget != null)
            updateLoadingWidget(_loadingWidget);
        _browserWidget = createBrowserWidget();
        if (_browserWidget != null)
            updateBrowserWidget(_browserWidget);
        _gotoWidget = createGotoWidget();
        if (_gotoWidget != null)
            updateGotoWidget(_gotoWidget);
        _pageSizesWidget = createPageSizeWidget();
        if (_pageSizesWidget != null)
            updatePageSizeWidget(_pageSizesWidget);
        // Combine all the above created widgets
        Widget panel = create();
        initWidget(panel);
        setStyleName(STYLE);
    }

    public PagingBar(Messages messages, int page, int size, int pageSize, int[] pageSizes) {
        this(page, size, pageSize, pageSizes);
        _messages = messages;
    }

    protected Widget create() {
        HorizontalPanel panel = new HorizontalPanel();
        panel.setSpacing(0);
        panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
        if (_positionWidget != null)
            panel.add(_positionWidget);
        if (_loadingWidget != null)
            panel.add(_loadingWidget);
        if (_browserWidget != null)
            panel.add(_browserWidget);
        panel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
        if (_gotoWidget != null)
            panel.add(_gotoWidget);
        if (_pageSizesWidget != null)
            panel.add(_pageSizesWidget);
        return panel;
    }

    protected Widget createPositionWidget() {
        Label label = new Label();
        label.setStylePrimaryName(STYLE_POSITION);
        return label;
    }

    protected void updatePositionWidget(Widget widget) {
        int pos = getPosition();
        int pos1 = pos + 1;
        String s;

        if (_pageSize > 1) {
            int pos2 = pos + _pageSize > _size ? _size : pos + _pageSize;
            if (_size > _limit) {
                s = _messages.rangelimit(pos1, pos2, _size, _limit);
            } else {
                s = _messages.range(pos1, pos2, _size);
            }
        } else {
            if (_size > _limit) {
                s = _messages.poslimit(pos1, _size, _limit);
            } else {
                s = _messages.pos(pos1, _size);
            }
        }
        ((Label) widget).setText(s);
        widget.setVisible(_size > 0);
    }

    protected Widget createLoadingWidget() {
        PushButton loading = new PushButton();
        loading.setStylePrimaryName(STYLE_LOADING);
        return loading;
    }

    protected void updateLoadingWidget(Widget widget) {
        ((PushButton) widget).setEnabled(_loading);
    }

    protected Widget createBrowserWidget() {
        HorizontalPanel panel = new HorizontalPanel();
        panel.setStylePrimaryName(STYLE_BROWSER);
        return panel;
    }

    protected void updateBrowserWidget(Widget widget) {
        HorizontalPanel panel = (HorizontalPanel) widget;
        int minpage = _page > 2 ? _page - 2 : 0;
        int maxpage = minpage + 4;
        if (maxpage >= _pages) {
            maxpage = _pages - 1;
            minpage = _pages > 4 ? _pages - 4 : 0;
        }
        panel.clear();
        panel.add(createBrowserItemWidget(FIRST, _page > 0));
        panel.add(createBrowserItemWidget(PREV, _page > 0));
        for (int i = minpage; i <= maxpage; ++i) {
            panel.add(createBrowserItemWidget(String.valueOf(i + 1), i != _page));
        }
        panel.add(createBrowserItemWidget(NEXT, _page < _pages - 1));
        panel.add(createBrowserItemWidget(LAST, _page < _pages - 1));
        widget.setVisible(_size > 0);
    }

    protected Widget createBrowserItemWidget(final int type, boolean enabled) {
        final ClickHandler clickHandler = new ClickHandler() {
            public void onClick(ClickEvent event) {
                switch (type) {
                case FIRST:
                    _page = 0;
                    break;
                case PREV:
                    --_page;
                    break;
                case NEXT:
                    ++_page;
                    break;
                case LAST:
                    _page = _pages - 1;
                    break;
                }
                fireChange();
            }
        };
        PushButton button = new PushButton();
        button.setStylePrimaryName(STYLES_BROWSER[type]);
        button.setEnabled(enabled);
        if (enabled)
            button.addClickHandler(clickHandler);
        return button;
    }

    protected Widget createBrowserItemWidget(String text, boolean enabled) {
        Label label = new Label(text);
        label.setStylePrimaryName(STYLE_PAGE);
        if (enabled) {
            label.addStyleDependentName(STYLE_ENABLED);
            label.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent event) {
                    String text = ((Label) event.getSource()).getText();
                    _page = Integer.parseInt(text) - 1;
                    fireChange();
                }
            });
        }
        return label;
    }

    protected Widget createGotoWidget() {
        final TextBox gotoPage = new TextBox();
        int maxlen = String.valueOf(computeNumPages()).length();
        gotoPage.setMaxLength(maxlen);
        gotoPage.setVisibleLength(maxlen);
        final PushButton go = new PushButton();
        go.setStylePrimaryName(STYLE_GOTO_BUTTON);
        go.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                setPage(Integer.parseInt(gotoPage.getText()) - 1);
                gotoPage.setText("");
                go.setEnabled(false);
                fireChange();
            }
        });
        go.setEnabled(false);
        gotoPage.addKeyDownHandler(new KeyDownHandler() {
            public void onKeyDown(final KeyDownEvent event) {
                final int keyCode = event.getNativeKeyCode();
                DeferredCommand.addCommand(new Command() {
                    public void execute() {
                        int page = -1;
                        try {
                            page = Integer.parseInt(gotoPage.getText()) - 1;
                        } catch (NumberFormatException e) {
                        }
                        go.setEnabled(page >= 0 && page < computeNumPages());
                        if (keyCode == KeyCodes.KEY_ENTER && go.isEnabled()) {
                            setPage(Integer.parseInt(gotoPage.getText()) - 1);
                            gotoPage.setText("");
                            go.setEnabled(false);
                            fireChange();
                        }
                    }
                });
            }
        });

        HorizontalPanel panel = new HorizontalPanel();
        panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
        panel.add(new HTML(_messages.go()));
        panel.add(gotoPage);
        panel.add(go);
        panel.setStylePrimaryName(STYLE_GOTO);
        return panel;
    }

    protected void updateGotoWidget(Widget widget) {
        widget.setVisible(computeNumPages() > 1);
        // Update allowed number of characters in the goto page textbox in case page size has changed (Yuck!)
        if (widget instanceof HorizontalPanel) {
            HorizontalPanel panel = (HorizontalPanel) widget;
            if (panel.getWidgetCount() == 3 && panel.getWidget(1) instanceof TextBox) {
                TextBox gotoPage = (TextBox) panel.getWidget(1);
                int maxlen = String.valueOf(computeNumPages()).length();
                gotoPage.setMaxLength(maxlen);
                gotoPage.setVisibleLength(maxlen);
            }
        }
    }

    protected Widget createPageSizeWidget() {
        HorizontalPanel panel = new HorizontalPanel();
        panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
        panel.add(new HTML(_messages.pagesize1()));
        panel.add(new ListBox());
        panel.add(new HTML(_messages.pagesize2()));
        panel.setStylePrimaryName(STYLE_PAGESIZE);
        return panel;
    }

    protected void updatePageSizeWidget(Widget widget) {
        if (_pageSizes != null) {
            final ListBox sizes = (ListBox) ((HorizontalPanel) _pageSizesWidget).getWidget(1);
            sizes.clear();
            for (int i = 0; i < _pageSizes.length; ++i) {
                sizes.addItem(String.valueOf(_pageSizes[i]));
                if (_pageSize == _pageSizes[i])
                    sizes.setSelectedIndex(i);
            }
            sizes.addChangeHandler(new ChangeHandler() {
                public void onChange(ChangeEvent event) {
                    int i = sizes.getSelectedIndex();
                    if (i >= 0) {
                        setPageSize(Integer.parseInt(sizes.getItemText(i)));
                        setPage(0);
                        fireChange();
                    }
                }
            });
        }
        widget.setVisible(_size > 0 && _pageSizes != null && _pageSizes.length > 1);
    }

    /**
     * Returns the offset of the first item.
     * @return Zero based offset.
     */
    public int getPosition() {
        int pos = _page * _pageSize;
        pos = Math.min(pos, getLimitedSize() - (_size % _pageSize));
        return pos < 0 ? 0 : pos;
    }

    /**
     * Sets the page number
     * @param page
     */
    public void setPage(int page) {
        _page = page;
    }

    public int getPageSize() {
        return _pageSize;
    }

    /**
     * Sets the Page size (Records per page)
     * @param pageSize
     */
    public void setPageSize(int pageSize) {
        _pageSize = pageSize;
        _pages = computeNumPages();
        update();
    }

    /**
     * Sets the total size of items
     * @param size
     */
    public void setSize(int size) {
        _size = size;
        _pages = computeNumPages();
        update();
    }

    public int getSize() {
        return _size;
    }

    /**
     * Sets the limits for total number items and number of pages
     * @param limit
     */
    public void setLimit(int limit) {
        _limit = limit;
        _pages = computeNumPages();
    }

    /**
     * Sets loading status.
     * @param loading
     */
    public void setLoading(boolean loading) {
        _loading = loading;
        updateLoadingWidget(_loadingWidget);
    }

    /**
     * Updates the status of the PagingBar.
     */
    public void update() {
        if (_positionWidget != null)
            updatePositionWidget(_positionWidget);
        if (_browserWidget != null) {
            updateBrowserWidget(_browserWidget);
            _browserWidget.setVisible(computeNumPages() > 1);
        }
        if (_gotoWidget != null)
            updateGotoWidget(_gotoWidget);
        if (_pageSizesWidget != null)
            _pageSizesWidget.setVisible(_size > 0 && _pageSizes != null && _pageSizes.length > 1);
        setVisible(computeNumPages() > 0);
    }

    /**
     * The fireChange method is invoked when any click event or change event
     * occurs. It fires a change event for all listeners and updates the PagingBar.
     */
    protected void fireChange() {
        ValueChangeEvent.fire(this, getPosition());
        update();
    }

    @Override
    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Integer> handler) {
        return this.addHandler(handler, ValueChangeEvent.getType());
    }

    /**
     * Returns the computed number of pages
     * @return Number of pages.
     */
    protected int computeNumPages() {
        return (getLimitedSize() + _pageSize - 1) / _pageSize;
    }

    /**
     * Returns the limit or number of items.
     */
    protected int getLimitedSize() {
        return _size > _limit ? _limit : _size;
    }
}