package com.dgex.offspring.swt.table; import java.util.Arrays; import java.util.List; import org.apache.log4j.Logger; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; public class PaginationContainer extends Composite { static Logger logger = Logger.getLogger(PaginationContainer.class); private final Label pageLabel; private PaginatedContentProvider contentProvider; private ColumnViewer viewer; private final Link previousLink; private final Link nextLink; private final Composite viewerComposite; static class PaginatedContentProvider implements IStructuredContentProvider { private final IStructuredContentProvider contentProvider; private final PaginationContainer container; private final int pageSize; private Pageable<Object> pageable = null; private int currentPage = 1; private int pageCount = 1; private int nextPage = 0; private int previousPage = 0; public PaginatedContentProvider(PaginationContainer container, IStructuredContentProvider contentProvider, int pageSize) { this.container = container; this.contentProvider = contentProvider; this.pageSize = pageSize; } @Override public void dispose() { contentProvider.dispose(); } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { this.contentProvider.inputChanged(viewer, oldInput, newInput); } private int calculatePages(int count) { if (pageSize > 0) { if (count % pageSize == 0) return count / pageSize; else return (count / pageSize) + 1; } return 0; } @Override public Object[] getElements(Object inputElement) { if (contentProvider instanceof IPageableStructeredContentProvider) { IPageableStructeredContentProvider cp = (IPageableStructeredContentProvider) contentProvider; this.pageCount = calculatePages(cp.getElementCount()); this.currentPage = currentPage <= 1 ? 1 : currentPage; // cp.setPageSize(pageSize); cp.setCurrentPage(Math.min(currentPage, pageCount)); this.nextPage = currentPage < pageCount ? currentPage + 1 : 0; this.previousPage = currentPage > 1 ? currentPage - 1 : 0; this.container.updateButtons(); logger.info("getElements() START"); Object[] elements = cp.getElements(inputElement); logger.info("getElements() END returns=" + elements.length); return elements; } else { Object[] elements = this.contentProvider.getElements(inputElement); this.pageable = new Pageable<Object>(Arrays.asList(elements), pageSize); this.pageable .setPage(Math.min(currentPage, this.pageable.getMaxPages())); this.pageCount = pageable.getMaxPages(); this.currentPage = pageable.getPage(); this.nextPage = pageable.getNextPage(); this.previousPage = pageable.getPreviousPage(); this.container.updateButtons(); List<Object> pagedList = this.pageable.getListForPage(); return pagedList.toArray(new Object[pagedList.size()]); } } public int getPageCount() { return pageCount; } public int getCurrentPage() { return currentPage; } public int nextPage() { return nextPage; } public int previousPage() { return previousPage; } public void setPage(int currentPage) { this.currentPage = Math.min(currentPage, getPageCount()); } }; public PaginationContainer(Composite parent, int style) { super(parent, style); GridLayoutFactory.fillDefaults().numColumns(3).margins(2, 0).spacing(2, 0) .applyTo(this); previousLink = new Link(this, SWT.NONE); previousLink.setVisible(false); GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.CENTER) .exclude(true).applyTo(previousLink); previousLink.setText("<A>previous</A>"); previousLink.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { final int previousPage = contentProvider.previousPage(); if (previousPage != contentProvider.getCurrentPage()) { BusyIndicator.showWhile(getDisplay(), new Runnable() { @Override public void run() { contentProvider.setPage(previousPage); viewer.refresh(); } }); } } }); nextLink = new Link(this, SWT.NONE); nextLink.setVisible(false); GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.CENTER) .exclude(true).applyTo(nextLink); nextLink.setText("<A>next</A>"); nextLink.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { final int nextPage = contentProvider.nextPage(); if (nextPage != contentProvider.getCurrentPage()) { BusyIndicator.showWhile(getDisplay(), new Runnable() { @Override public void run() { contentProvider.setPage(nextPage); viewer.refresh(); } }); } } }); pageLabel = new Label(this, SWT.NONE); pageLabel.setVisible(false); GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).grab(true, false) .exclude(true).applyTo(pageLabel); viewerComposite = new Composite(this, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true) .span(3, 1).applyTo(viewerComposite); } public Composite getViewerParent() { return viewerComposite; } private void updateButtons() { int pageCount = this.contentProvider.getPageCount(); if (pageCount > 1) { setButtonsExcluded(false); int currentPage = this.contentProvider.getCurrentPage(); previousLink.setEnabled(currentPage > 1); nextLink.setEnabled(currentPage < pageCount); pageLabel.setText(currentPage + "/" + pageCount); pageLabel.pack(); } else { setButtonsExcluded(true); } layout(); } private void setButtonsExcluded(boolean exclude) { ((GridData) previousLink.getLayoutData()).exclude = exclude; ((GridData) nextLink.getLayoutData()).exclude = exclude; ((GridData) pageLabel.getLayoutData()).exclude = exclude; previousLink.setVisible(!exclude); nextLink.setVisible(!exclude); pageLabel.setVisible(!exclude); } /** * The TableViewer is already constructed and uses this composite as it's * parent. This works because in the constructor we create all other children * of this composite so they will be rendered before the table viewer. You * dont need to set any layout data on the table viewer, this method will take * care of that. * * @param viewer */ public void setTableViewer(ColumnViewer viewer, int pageSize) { this.viewer = viewer; IStructuredContentProvider inner = ((IGenericViewer) viewer) .getGenericTable().getContentProvider(); if (inner instanceof IPageableStructeredContentProvider) { ((IPageableStructeredContentProvider) inner).setPageSize(pageSize); } contentProvider = new PaginatedContentProvider(this, inner, pageSize); viewer.setContentProvider(contentProvider); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true) .span(5, 1).applyTo(viewer.getControl()); } }