Java/Collections Data Structure/Paging
Implementation of PaginatedList backed by an ArrayList
/*
* Copyright 2004 Clinton Begin
*
* 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.
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* Implementation of PaginatedList backed by an ArrayList
*
*/
public class PaginatedArrayList implements PaginatedList {
private static final ArrayList EMPTY_LIST = new ArrayList(0);
private List list;
private List page;
private int pageSize;
private int index;
/**
* @param pageSize
*/
public PaginatedArrayList(int pageSize) {
this.pageSize = pageSize;
this.index = 0;
this.list = new ArrayList();
repaginate();
}
/**
* Constructor to set the initial size and the page size
*
* @param initialCapacity -
* the initial size
* @param pageSize -
* the page size
*/
public PaginatedArrayList(int initialCapacity, int pageSize) {
this.pageSize = pageSize;
this.index = 0;
this.list = new ArrayList(initialCapacity);
repaginate();
}
/**
* Constructor to create an instance using an existing collection
*
* @param c -
* the collection to build the instance with
* @param pageSize -
* the page size
*/
public PaginatedArrayList(Collection c, int pageSize) {
this.pageSize = pageSize;
this.index = 0;
this.list = new ArrayList(c);
repaginate();
}
private void repaginate() {
if (list.isEmpty()) {
page = EMPTY_LIST;
} else {
int start = index * pageSize;
int end = start + pageSize - 1;
if (end >= list.size()) {
end = list.size() - 1;
}
if (start >= list.size()) {
index = 0;
repaginate();
} else if (start < 0) {
index = list.size() / pageSize;
if (list.size() % pageSize == 0) {
index--;
}
repaginate();
} else {
page = list.subList(start, end + 1);
}
}
}
/* List accessors (uses page) */
public int size() {
return page.size();
}
public boolean isEmpty() {
return page.isEmpty();
}
public boolean contains(Object o) {
return page.contains(o);
}
public Iterator iterator() {
return page.iterator();
}
public Object[] toArray() {
return page.toArray();
}
public Object[] toArray(Object a[]) {
return page.toArray(a);
}
public boolean containsAll(Collection c) {
return page.containsAll(c);
}
public Object get(int index) {
return page.get(index);
}
public int indexOf(Object o) {
return page.indexOf(o);
}
public int lastIndexOf(Object o) {
return page.lastIndexOf(o);
}
public ListIterator listIterator() {
return page.listIterator();
}
public ListIterator listIterator(int index) {
return page.listIterator(index);
}
public List subList(int fromIndex, int toIndex) {
return page.subList(fromIndex, toIndex);
}
/* List mutators (uses master list) */
public boolean add(Object o) {
boolean b = list.add(o);
repaginate();
return b;
}
public boolean remove(Object o) {
boolean b = list.remove(o);
repaginate();
return b;
}
public boolean addAll(Collection c) {
boolean b = list.addAll(c);
repaginate();
return b;
}
public boolean addAll(int index, Collection c) {
boolean b = list.addAll(index, c);
repaginate();
return b;
}
public boolean removeAll(Collection c) {
boolean b = list.removeAll(c);
repaginate();
return b;
}
public boolean retainAll(Collection c) {
boolean b = list.retainAll(c);
repaginate();
return b;
}
public void clear() {
list.clear();
repaginate();
}
public Object set(int index, Object element) {
Object o = list.set(index, element);
repaginate();
return o;
}
public void add(int index, Object element) {
list.add(index, element);
repaginate();
}
public Object remove(int index) {
Object o = list.remove(index);
repaginate();
return o;
}
/* Paginated List methods */
public int getPageSize() {
return pageSize;
}
public boolean isFirstPage() {
return index == 0;
}
public boolean isMiddlePage() {
return !(isFirstPage() || isLastPage());
}
public boolean isLastPage() {
return list.size() - ((index + 1) * pageSize) < 1;
}
public boolean isNextPageAvailable() {
return !isLastPage();
}
public boolean isPreviousPageAvailable() {
return !isFirstPage();
}
public boolean nextPage() {
if (isNextPageAvailable()) {
index++;
repaginate();
return true;
} else {
return false;
}
}
public boolean previousPage() {
if (isPreviousPageAvailable()) {
index--;
repaginate();
return true;
} else {
return false;
}
}
public void gotoPage(int pageNumber) {
index = pageNumber;
repaginate();
}
public int getPageIndex() {
return index;
}
}
/*
* Copyright 2004 Clinton Begin
*
* 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.
*/
/**
* Interface for lists that support paging
*
*/
interface PaginatedList extends List {
/**
* Returns the maximum number of items per page
*
* @return The maximum number of items per page.
*/
public int getPageSize();
/**
* Is the current page the first page?
*
* @return True if the current page is the first page or if only a single page
* exists.
*/
public boolean isFirstPage();
/**
* Is the current page a middle page (ie not first or last)?
*
* @return True if the current page is not the first or last page, and more
* than one page exists (always returns false if only a single page
* exists).
*/
public boolean isMiddlePage();
/**
* Is the current page the last page?
*
* @return True if the current page is the last page or if only a single page
* exists.
*/
public boolean isLastPage();
/**
* Is a page available after the current page?
*
* @return True if the next page is available
*/
public boolean isNextPageAvailable();
/**
* Is a page available before the current page?
*
* @return True if the previous page is available
*/
public boolean isPreviousPageAvailable();
/**
* Moves to the next page after the current page. If the current page is the
* last page, wrap to the first page.
*
* @return True if the page changed
*/
public boolean nextPage();
/**
* Moves to the page before the current page. If the current page is the first
* page, wrap to the last page.
*
* @return True if the page changed
*/
public boolean previousPage();
/**
* Moves to a specified page. If the specified page is beyond the last page,
* wrap to the first page. If the specified page is before the first page,
* wrap to the last page.
*
* @param pageNumber
* The page to go to
*/
public void gotoPage(int pageNumber);
/**
* Returns the current page index, which is a zero based integer. All
* paginated list implementations should know what index they are on, even if
* they don"t know the ultimate boundaries (min/max).
*
* @return The current page
*/
public int getPageIndex();
}
Paging over a collection
/*
* Copyright (c) 2003-2006, Simon Brown
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither the name of Pebble nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
import java.util.List;
/**
* Helper class that implements paging over a collection.
*
* @author Simon Brown
*/
public class Pageable<T> {
/** the default page size */
public static final int DEFAULT_PAGE_SIZE = 10;
private static final int PAGE_WINDOW = 10;
/** the list over which this class is paging */
private List<T> list;
/** the page size */
private int pageSize = DEFAULT_PAGE_SIZE;
/** the current page */
private int page;
/** the starting index */
private int startingIndex;
/** the ending index */
private int endingIndex;
/** the maximum number of pages */
private int maxPages;
/**
* Creates a new instance with the specified list.
*
* @param list a List
*/
public Pageable(List<T> list) {
this.list = list;
this.page = 1;
this.maxPages = 1;
calculatePages();
}
private void calculatePages() {
if (pageSize > 0) {
// calculate how many pages there are
if (list.size() % pageSize == 0) {
maxPages = list.size() / pageSize;
} else {
maxPages = (list.size() / pageSize) + 1;
}
}
}
/**
* Gets the list that this instance is paging over.
*
* @return a List
*/
public List<T> getList() {
return this.list;
}
/**
* Gets the subset of the list for the current page.
*
* @return a List
*/
public List<T> getListForPage() {
return list.subList(startingIndex, endingIndex);
}
/**
* Gets the page size.
*
* @return the page size as an int
*/
public int getPageSize() {
return this.pageSize;
}
/**
* Sets the page size.
*
* @param pageSize the page size as an int
*/
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
calculatePages();
}
/**
* Gets the page.
*
* @return the page as an int
*/
public int getPage() {
return this.page;
}
/**
* Sets the page size.
*
* @param p the page as an int
*/
public void setPage(int p) {
if (p >= maxPages) {
this.page = maxPages;
} else if (p <= 1) {
this.page = 1;
} else {
this.page = p;
}
// now work out where the sub-list should start and end
startingIndex = pageSize * (page-1);
if (startingIndex < 0) {
startingIndex = 0;
}
endingIndex = startingIndex + pageSize;
if (endingIndex > list.size()) {
endingIndex = list.size();
}
}
/**
* Gets the maximum number of pages.
*
* @return the maximum number of pages as an int
*/
public int getMaxPages() {
return this.maxPages;
}
/**
* Determines whether there is a previous page and gets the page number.
*
* @return the previous page number, or zero
*/
public int getPreviousPage() {
if (page > 1) {
return page-1;
} else {
return 0;
}
}
/**
* Determines whether there is a next page and gets the page number.
*
* @return the next page number, or 0
*/
public int getNextPage() {
if (page < maxPages) {
return page+1;
} else {
return 0;
}
}
/**
* Gets the minimum page in the window.
*
* @return the page number
*/
public int getMinPageRange() {
if (getPage() > PAGE_WINDOW) {
return getPage() - PAGE_WINDOW;
} else {
return 1;
}
}
/**
* Gets the maximum page in the window.
*
* @return the page number
*/
public int getMaxPageRange() {
if (getPage() < (getMaxPages() - PAGE_WINDOW)) {
return getPage() + PAGE_WINDOW;
} else {
return getMaxPages();
}
}
}