blob: 430377010a78df08888e9ea99c2a9dc646be488e [file] [log] [blame]
/*
* 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();
}
}