Java/Collections Data Structure/Paging
Implementation of PaginatedList backed by an ArrayList
<source lang="java">
/*
* 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();
}
</source>
Paging over a collection
<source lang="java">
/*
* 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(); } }
}
</source>