blob: add3acfad5420d5aba287243e697e3e59d5046d1 [file] [log] [blame]
// Copyright 2004, 2005 The Apache Software Foundation
//
// 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.
package org.apache.tapestry.vlib.components;
import java.rmi.RemoteException;
import org.apache.tapestry.AbstractComponent;
import org.apache.tapestry.IActionListener;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.annotations.ComponentClass;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.annotations.Persist;
import org.apache.tapestry.event.PageBeginRenderListener;
import org.apache.tapestry.event.PageEvent;
import org.apache.tapestry.vlib.OperationsUser;
import org.apache.tapestry.vlib.ejb.Book;
import org.apache.tapestry.vlib.ejb.IBookQuery;
import org.apache.tapestry.vlib.services.RemoteCallback;
/**
* Implements a paging browser for the results of a {@link IBookQuery}. Renders its body multiple
* times, once for each book provided by the query.
*
* @author Howard Lewis Ship
*/
@ComponentClass(allowInformalParameters = true, allowBody = true)
public abstract class Browser extends AbstractComponent implements PageBeginRenderListener,
OperationsUser
{
/**
* Default for the page size; the number of results viewed on each page.
*/
public static final int DEFAULT_PAGE_SIZE = 15;
/**
* The maximum number of items to display on a page.
*/
private int _pageSize = DEFAULT_PAGE_SIZE;
@Parameter(required = true)
public abstract IBookQuery getQuery();
@Persist
public abstract int getResultCount();
public abstract void setResultCount(int resultCount);
@Persist
public abstract int getCurrentPage();
public abstract void setCurrentPage(int currentPage);
public abstract void setElement(String element);
@Parameter
public abstract String getElement();
@Parameter(required = true)
public abstract void setValue(Object value);
@Parameter(required = true)
public abstract IActionListener getListener();
@Persist
public abstract Object[] getPageResults();
public abstract void setPageResults(Object[] pageResults);
/**
* Invoked by the container when the query (otherwise accessed via the query parameter) changes.
* Re-caches the number of results and sets the current page back to 1.
*/
public void initializeForResultCount(int resultCount)
{
setResultCount(resultCount);
setCurrentPage(1);
setPageCount(computePageCount());
}
@Persist
public abstract int getPageCount();
public abstract void setPageCount(int pageCount);
private int computePageCount()
{
// For 0 ... pageSize elements, its just one page.
int resultCount = getResultCount();
if (resultCount <= _pageSize)
return 1;
// We need the number of results divided by the results per page.
int result = resultCount / _pageSize;
// If there's any left-over, then we need an additional page.
if (resultCount % _pageSize > 0)
result++;
return result;
}
/**
* Invoked to change the displayed page number.
*
* @param page
* page to display, numbered from one. The currentPage property will be updated. The
* value is constrained to fit in the valid range of pages for the component.
*/
public void jump(int page)
{
if (page < 2)
{
setCurrentPage(1);
return;
}
int pageCount = getPageCount();
if (page > getPageCount())
{
setCurrentPage(pageCount);
return;
}
setCurrentPage(page);
}
public boolean getDisableBack()
{
return getCurrentPage() <= 1;
}
public boolean getDisableNext()
{
return getCurrentPage() >= getPageCount();
}
public String getRange()
{
int currentPage = getCurrentPage();
int resultCount = getResultCount();
int low = (currentPage - 1) * _pageSize + 1;
int high = Math.min(currentPage * _pageSize, resultCount);
return low + " - " + high;
}
protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
{
Object[] books = getPageResults();
int count = Tapestry.size(books);
String element = getElement();
for (int i = 0; i < count; i++)
{
setValue(books[i]);
if (element != null)
{
writer.begin(element);
renderInformalParameters(writer, cycle);
}
renderBody(writer, cycle);
if (element != null)
writer.end();
}
}
protected void finishLoad()
{
setElement("tr");
}
public void pageBeginRender(final PageEvent event)
{
int resultCount = getResultCount();
int currentPage = getCurrentPage();
final int low = (currentPage - 1) * _pageSize;
final int high = Math.min(currentPage * _pageSize, resultCount) - 1;
if (low > high)
return;
RemoteCallback<Book[]> callback = new RemoteCallback()
{
public Book[] doRemote() throws RemoteException
{
try
{
return getQuery().get(low, high - low + 1);
}
catch (RemoteException ex)
{
getListener().actionTriggered(Browser.this, event.getRequestCycle());
throw ex;
}
}
};
Book[] pageResults = getRemoteTemplate().execute(
callback,
"Error retrieving query results.");
setPageResults(pageResults);
}
}