Java tutorial
/* * 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; } }