package net.frontlinesms.ui.handler;
import net.frontlinesms.ui.ThinletUiEventHandler;
import net.frontlinesms.ui.UiGeneratorController;
import net.frontlinesms.ui.i18n.InternationalisationUtils;
import net.frontlinesms.ui.i18n.TextResourceKeyOwner;
/**
* Thinlet UI event handler for paging lists and tables.
* @author Alex Anderson <alex@frontlinesms.com>
*/
@TextResourceKeyOwner
public class ComponentPagingHandler implements ThinletUiEventHandler {
//> CONSTANTS
/** Thinlet UI layout file for paging controls */
private static final String UI_FILE_PAGE_PANEL = "/ui/core/util/pnPageControls.xml";
/** I18N Text key: "Page X of Y" */
private static final String I18N_KEY_PAGES_X_OF_Y = "common.page.number";
/** UI Component name for */
private static final String COMPONENT_BT_NEXT_PAGE = "btNextPage";
/** UI Component name for */
private static final String COMPONENT_BT_PREVIOUS_PAGE = "btPreviousPage";
//> INSTANCE VARIABLES
/** {@link UiGeneratorController} that the paging and list components are attached to */
private final UiGeneratorController ui;
/** The panel containing the paging controls. */
private Object panel;
/** The list or table that we are paging */
private final Object list;
/** The provider of items to display in this list. */
private final PagedComponentItemProvider itemProvider;
/** The current page number. This is zero-indexed. */
private int currentPage;
/** The total number of pages. */
private int totalPages;
/** The total number of items this list contains, across all pages. */
private int totalListItems;
/** The maximum items to display per page. */
private final int maxItemsPerPage;
//> CONSTRUCTORS
/**
* Creates a new {@link ComponentPagingHandler}.
* @param ui The {@link UiGeneratorController} instance that this is tied to.
* @param itemProvider The class which provides items to place in the list
* @param list The list that this will handle paging for.
*/
public ComponentPagingHandler(UiGeneratorController ui, PagedComponentItemProvider itemProvider, Object list) {
assert(ui!=null) : "Must supply non-null UI";
assert(itemProvider!=null) : "Must supply non-null itemProvider";
assert(list!=null) : "Must supply non-null list";
this.ui = ui;
this.itemProvider = itemProvider;
this.list = list;
this.maxItemsPerPage = ui.getProperties().getItemsPerPage();
}
//> ACCESSORS
/**
* <p>Sets the value of {@link #currentPage}.</p>
* <p>N.B. this method does NOT refresh the view, it merely sets the value of the current page.</p>
* @param currentPage the page number to set
*/
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
/** @return the maximum number of items that this will display per page. */
public int getMaxItemsPerPage() {
return maxItemsPerPage;
}
/**
* Loads the panel and returns it for adding to the UI.
* @return A new instance of the thinlet panel for adding to the UI.
*/
public Object getPanel() {
this.panel = ui.loadComponentFromFile(UI_FILE_PAGE_PANEL, this);
return panel;
}
/** @return {@link #list} */
public Object getList() {
return list;
}
/** Refresh the paging panel and its associated list. */
public void refresh() {
this.refreshList();
}
//> UI EVENT METHODS
/** Turn to the previous page. */
public void previousPage() {
if(this.currentPage > 0) {
--this.currentPage;
refreshList();
}
}
/** Turn to the previous page. */
public void nextPage() {
if(currentPage < this.totalPages-1) {
++this.currentPage;
refreshList();
}
}
//> UI HELPER METHODS
/** Update the page count internally, and that displayed. */
private void updatePageCount(int totalItemCount) {
// Update the page count etc.
this.totalListItems = totalItemCount;
this.totalPages = (int) Math.ceil(((double)this.totalListItems) / this.maxItemsPerPage);
// Make sure that the page has not got out of range
if(totalPages == 0) {
currentPage = 0;
} else if(this.currentPage >= this.totalPages) {
this.currentPage = this.totalPages - 1;
}
// Update the paging text, and enable previous and next page buttons as appropriate
ui.setText(ui.find(this.panel, "lbPageNumber"),
InternationalisationUtils.getI18nString(I18N_KEY_PAGES_X_OF_Y,
Integer.toString(this.currentPage + 1),
Integer.toString(Math.max(1, this.totalPages))));
ui.setEnabled(ui.find(panel, COMPONENT_BT_PREVIOUS_PAGE), this.currentPage > 0);
ui.setEnabled(ui.find(panel, COMPONENT_BT_NEXT_PAGE), this.currentPage < this.totalPages - 1);
}
/** Load the list items for the {@link #currentPage} and display them. */
private synchronized void refreshList() {
int startIndex = this.currentPage*this.maxItemsPerPage;
PagedListDetails details = this.itemProvider.getListDetails(this.list, startIndex, this.maxItemsPerPage);
updatePageCount(details.getTotalItemCount());
// Refresh the contents of the list
ui.removeAll(this.list);
for(Object newChild : details.getListItems()) {
ui.add(this.list, newChild);
if(details.isSelected(newChild)) {
ui.setSelected(newChild, true);
}
}
}
}