/* * $Id$ * $URL$ */ package org.subethamail.web.model; import java.util.ArrayList; import java.util.List; /** * Models which can be paginated (take a skip and count, etc) * * @author Jeff Schnitzer */ public class PaginateModel { /** */ public static final int DEFAULT_COUNT = 100; /** Input */ int count = DEFAULT_COUNT; public int getCount() { return this.count; } public void setCount(int value) { this.count = value; } /** Input */ int skip = 0; public int getSkip() { return this.skip; } public void setSkip(int value) { this.skip = value; } /** Output */ int totalCount; public int getTotalCount() { return this.totalCount; } /** * Must be called during action execution */ public void setTotalCount(int value) { this.totalCount = value; } /** */ public boolean isHead() { return this.skip == 0; } /** */ public boolean isTail() { return this.skip >= this.getLast(); } /** */ public int getPrevious() { return Math.max(0, this.skip - this.count); } /** */ public int getNext() { return Math.min(this.getLast(), this.skip + this.count); } /** * @return the last page-oriented skip value */ public int getLast() { int pageCount = this.totalCount / this.count; if (this.totalCount == (pageCount * this.count)) return (pageCount - 1) * this.count; else return pageCount * this.count; } /** * @return true if there is only one page. */ public boolean isSinglePage() { return this.totalCount <= this.count; } /** * @return the 1-based index of the item being displayed first */ public int getDisplayedFirst() { return this.skip + 1; } /** * @return the 1-based index of the item being displayed last */ public int getDisplayedLast() { int theoretical = this.skip + this.count; if (theoretical > this.totalCount) return this.totalCount; else return theoretical; } /** * Allows the display of pagination like this: * http://developer.yahoo.net/ypatterns/pattern_searchpagination.php */ public List<Page> getPaginationPages() { List<Page> retVal = new ArrayList<Page>(10); // This is tricky. Just remember that page indexes are 0-based, // they only become 1-based displayNumbers at the last moment. int pageCount = this.totalCount / this.count; if (totalCount % this.count != 0) pageCount++; int lastPage = pageCount - 1; int currentPage = this.skip / this.count; if (currentPage > lastPage) currentPage = lastPage; int startingPage = currentPage - 5; int endingPage = currentPage + 4; // Maybe need to contract the starting page part if (startingPage < 0) { endingPage += Math.abs(startingPage); startingPage = 0; } // Maybe need to contract the ending page part if (endingPage > lastPage) { startingPage -= (endingPage - lastPage); endingPage = lastPage; } // Ending page contraction might have pushed starting page back too far if (startingPage < 0) startingPage = 0; for (int i=startingPage; i<=endingPage; i++) { retVal.add(new Page(i+1, i*this.count, i==currentPage)); } return retVal; } /** * A simple class to allow displaying search-type pagination. * Number is the 1-based page number suitable for display. */ public static class Page { int displayNumber; int skip; boolean current; public Page(int displayNumber, int skip, boolean current) { this.displayNumber = displayNumber; this.skip = skip; this.current = current; } /** */ public boolean isCurrent() { return this.current; } /** */ public int getDisplayNumber() { return this.displayNumber; } /** */ public int getSkip() { return this.skip; } } }