| /* |
| * Copyright 2010 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.cellview.client; |
| |
| import com.google.gwt.event.shared.HandlerRegistration; |
| import com.google.gwt.user.client.ui.Composite; |
| import com.google.gwt.view.client.HasRows; |
| import com.google.gwt.view.client.Range; |
| import com.google.gwt.view.client.RangeChangeEvent; |
| import com.google.gwt.view.client.RowCountChangeEvent; |
| |
| /** |
| * An abstract pager that exposes many methods useful for paging. |
| */ |
| public abstract class AbstractPager extends Composite { |
| |
| private HasRows display; |
| |
| /** |
| * If true, all operations should be limited to the data size. |
| */ |
| private boolean isRangeLimited = true; |
| |
| /** |
| * The last row count. |
| */ |
| private int lastRowCount; |
| |
| private HandlerRegistration rangeChangeHandler; |
| private HandlerRegistration rowCountChangeHandler; |
| |
| /** |
| * Get the {@link HasRows} being paged. |
| * |
| * @return the {@link HasRows} |
| */ |
| public HasRows getDisplay() { |
| return display; |
| } |
| |
| /** |
| * Get the page size. |
| * |
| * @return the page size, or -1 if the display is not set |
| */ |
| public int getPageSize() { |
| return display == null ? -1 : display.getVisibleRange().getLength(); |
| } |
| |
| /** |
| * Get the page start index. |
| * |
| * @return the page start index, or -1 if the display is not set |
| */ |
| public int getPageStart() { |
| return display == null ? -1 : display.getVisibleRange().getStart(); |
| } |
| |
| /** |
| * Check if the page should be limited to the actual data size. Defaults to |
| * true. |
| * |
| * @return true if the range is limited to the data size |
| */ |
| public boolean isRangeLimited() { |
| return isRangeLimited; |
| } |
| |
| /** |
| * Set whether or not the page range should be limited to the actual data |
| * size. If true, all operations will adjust so that there is always data |
| * visible on the page. |
| * |
| * @param isRangeLimited true to limit the range, false not to |
| */ |
| public void setRangeLimited(boolean isRangeLimited) { |
| this.isRangeLimited = isRangeLimited; |
| } |
| |
| /** |
| * Set the {@link HasRows} to be paged. |
| * |
| * @param display the {@link HasRows} |
| */ |
| public void setDisplay(HasRows display) { |
| // Remove the old handlers. |
| if (rangeChangeHandler != null) { |
| rangeChangeHandler.removeHandler(); |
| rangeChangeHandler = null; |
| } |
| if (rowCountChangeHandler != null) { |
| rowCountChangeHandler.removeHandler(); |
| rangeChangeHandler = null; |
| } |
| |
| // Set the new display. |
| this.display = display; |
| if (display != null) { |
| rangeChangeHandler = display.addRangeChangeHandler( |
| new RangeChangeEvent.Handler() { |
| public void onRangeChange(RangeChangeEvent event) { |
| if (AbstractPager.this.display != null) { |
| onRangeOrRowCountChanged(); |
| } |
| } |
| }); |
| rowCountChangeHandler = display.addRowCountChangeHandler( |
| new RowCountChangeEvent.Handler() { |
| public void onRowCountChange(RowCountChangeEvent event) { |
| if (AbstractPager.this.display != null) { |
| handleRowCountChange( |
| event.getNewRowCount(), event.isNewRowCountExact()); |
| } |
| } |
| }); |
| |
| // Initialize the pager. |
| onRangeOrRowCountChanged(); |
| } |
| } |
| |
| /** |
| * Go to the first page. |
| */ |
| protected void firstPage() { |
| setPage(0); |
| } |
| |
| /** |
| * <p> |
| * Get the current page index. |
| * </p> |
| * <p> |
| * Since the page start index can be set to any value, its possible to be |
| * between pages. In this case, the return value is the number of times |
| * {@link #previousPage()} can be called. |
| * </p> |
| * |
| * @return the page index, or -1 if the display is not set |
| */ |
| protected int getPage() { |
| if (display == null) { |
| return -1; |
| } |
| Range range = display.getVisibleRange(); |
| int pageSize = range.getLength(); |
| return (range.getStart() + pageSize - 1) / pageSize; |
| } |
| |
| /** |
| * Get the number of pages based on the data size. |
| * |
| * @return the page count, or -1 if the display is not set |
| */ |
| protected int getPageCount() { |
| if (display == null) { |
| return -1; |
| } |
| int pageSize = getPageSize(); |
| return (display.getRowCount() + pageSize - 1) / pageSize; |
| } |
| |
| /** |
| * Returns true if there is enough data such that a call to |
| * {@link #nextPage()} will succeed in moving the starting point of the table |
| * forward. |
| */ |
| protected boolean hasNextPage() { |
| if (display == null) { |
| return false; |
| } else if (!display.isRowCountExact()) { |
| return true; |
| } |
| Range range = display.getVisibleRange(); |
| return range.getStart() + range.getLength() < display.getRowCount(); |
| } |
| |
| /** |
| * Returns true if there is enough data to display a given number of |
| * additional pages. |
| */ |
| protected boolean hasNextPages(int pages) { |
| if (display == null) { |
| return false; |
| } |
| Range range = display.getVisibleRange(); |
| return range.getStart() + pages * range.getLength() < display.getRowCount(); |
| } |
| |
| /** |
| * Returns true if there is enough data such that the specified page is within |
| * range. |
| */ |
| protected boolean hasPage(int index) { |
| return display == null ? false : getPageSize() * index |
| < display.getRowCount(); |
| } |
| |
| /** |
| * Returns true if there is enough data such that a call to |
| * {@link #previousPage()} will succeed in moving the starting point of the |
| * table backward. |
| */ |
| protected boolean hasPreviousPage() { |
| return display == null ? false : getPageStart() > 0 |
| && display.getRowCount() > 0; |
| } |
| |
| /** |
| * Returns true if there is enough data to display a given number of previous |
| * pages. |
| */ |
| protected boolean hasPreviousPages(int pages) { |
| if (display == null) { |
| return false; |
| } |
| Range range = display.getVisibleRange(); |
| return (pages - 1) * range.getLength() < range.getStart(); |
| } |
| |
| /** |
| * Go to the last page. |
| */ |
| protected void lastPage() { |
| setPage(getPageCount() - 1); |
| } |
| |
| /** |
| * Set the page start to the last index that will still show a full page. |
| */ |
| protected void lastPageStart() { |
| if (display != null) { |
| setPageStart(display.getRowCount() - getPageSize()); |
| } |
| } |
| |
| /** |
| * Advance the starting row by 'pageSize' rows. |
| */ |
| protected void nextPage() { |
| if (display != null) { |
| Range range = display.getVisibleRange(); |
| setPageStart(range.getStart() + range.getLength()); |
| } |
| } |
| |
| /** |
| * Called when the range or row count changes. Implement this method to update |
| * the pager. |
| */ |
| protected abstract void onRangeOrRowCountChanged(); |
| |
| /** |
| * Move the starting row back by 'pageSize' rows. |
| */ |
| protected void previousPage() { |
| if (display != null) { |
| Range range = display.getVisibleRange(); |
| setPageStart(range.getStart() - range.getLength()); |
| } |
| } |
| |
| /** |
| * Go to a specific page. |
| * |
| * @param index the page index |
| */ |
| protected void setPage(int index) { |
| if (display != null |
| && (!isRangeLimited || !display.isRowCountExact() || hasPage(index))) { |
| // We don't use the local version of setPageStart because it would |
| // constrain the index, but the user probably wants to use absolute page |
| // indexes. |
| int pageSize = getPageSize(); |
| display.setVisibleRange(pageSize * index, pageSize); |
| } |
| } |
| |
| /** |
| * Set the page size of the display. |
| * |
| * @param pageSize the new page size |
| */ |
| protected void setPageSize(int pageSize) { |
| if (display != null) { |
| Range range = display.getVisibleRange(); |
| int pageStart = range.getStart(); |
| if (isRangeLimited && display.isRowCountExact()) { |
| pageStart = Math.min(pageStart, display.getRowCount() - pageSize); |
| } |
| pageStart = Math.max(0, pageStart); |
| display.setVisibleRange(pageStart, pageSize); |
| } |
| } |
| |
| /** |
| * Set the page start index. |
| * |
| * @param index the index |
| */ |
| protected void setPageStart(int index) { |
| if (display != null) { |
| Range range = display.getVisibleRange(); |
| int pageSize = range.getLength(); |
| if (isRangeLimited && display.isRowCountExact()) { |
| index = Math.min(index, display.getRowCount() - pageSize); |
| } |
| index = Math.max(0, index); |
| if (index != range.getStart()) { |
| display.setVisibleRange(index, pageSize); |
| } |
| } |
| } |
| |
| /** |
| * Called when the row count changes. Only called if display is non-null. |
| * |
| * @param rowCount the new row count |
| * @param isExact true if the row count is exact |
| */ |
| private void handleRowCountChange(int rowCount, boolean isExact) { |
| int oldRowCount = lastRowCount; |
| lastRowCount = display.getRowCount(); |
| |
| // If the row count has changed, limit the range. |
| if (isRangeLimited && oldRowCount != lastRowCount) { |
| setPageStart(getPageStart()); |
| } |
| |
| // Call user methods. |
| onRangeOrRowCountChanged(); |
| } |
| } |