/* * Copyright 2009-2011 the original author or authors. * * 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.jdal.vaadin.ui.table; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.annotation.PostConstruct; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jdal.annotation.SerializableProxy; import org.jdal.dao.Dao; import org.jdal.dao.Filter; import org.jdal.dao.Page; import org.jdal.dao.Page.Order; import org.jdal.dao.PageChangedEvent; import org.jdal.dao.PaginatorListener; import org.jdal.vaadin.ui.VaadinView; import org.jdal.vaadin.ui.form.FormDialog; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.dao.DataAccessException; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import com.vaadin.data.Container; import com.vaadin.data.Container.ItemSetChangeEvent; import com.vaadin.event.ItemClickEvent.ItemClickListener; import com.vaadin.ui.Alignment; import com.vaadin.ui.Component; import com.vaadin.ui.Notification; import com.vaadin.ui.Notification.Type; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window.CloseEvent; import com.vaadin.ui.Window.CloseListener; /** * Vaadin Table with paginator. Use a BeanItemContainer as * table datasource and request pages using a {@link Dao}. </p> * * @author Jose Luis Martin * @see org.jdal.dao.Dao * @param <T> bean type */ @Configurable public class PageableTable<T> extends TableComponent<T> implements PaginatorListener, Container.ItemSetChangeListener, CloseListener { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(PageableTable.class); /** persistentService */ @SerializableProxy private Dao<T, ?extends Serializable> service; /** external paginator */ private VaadinPaginator<T> paginator; /** page */ transient Page<T> page = new Page<T>(); /** Filter */ private Filter beanFilter; /** if true, pagesLength change to pageSize */ private boolean autoResize = true; /** if true, will create a editor when none configured */ private boolean autoCreateEditor = true; /** Filter editor */ private String filterEditor; /** Filter Form */ private VaadinView<Filter> filterForm; private String name; /** propagate service to editors */ private boolean propagateService = true; public PageableTable() { } public PageableTable(Class<T> entityClass) { super(entityClass); } @SuppressWarnings("unchecked") @PostConstruct public void init() { // build Component VerticalLayout verticalLayout = getVerticalLayout(); verticalLayout.setSizeUndefined(); verticalLayout.setSpacing(true); // filter if (filterEditor != null && filterForm == null) { filterForm = (VaadinView<Filter>) getGuiFactory().getView(filterEditor); } if (filterForm != null) { if (beanFilter != null) { filterForm.setModel(beanFilter); } else { beanFilter = filterForm.getModel(); } verticalLayout.addComponent((Component) filterForm.getPanel()); } // action group if (getActions().size() > 0) { verticalLayout.addComponent(createButtonBox()); } // table verticalLayout.addComponent(getTable()); verticalLayout.setExpandRatio(getTable(), 1.0f); // paginator if (this.paginator == null) { this.paginator = new VaadinPaginator<T>(); this.paginator.setMessageSource(getMessageSource()); } paginator.setModel(page); paginator.addPaginatorListener(this); paginator.setNativeButtons(isNativeButtons()); page.setPageableDataSource(getService()); // set external sorting, ie don't call Container.sort() getTable().setSorter(new PageSorter()); Component p = paginator.getPanel(); verticalLayout.addComponent(p); verticalLayout.setComponentAlignment(p, Alignment.MIDDLE_CENTER); getTable().setPageLength(page.getPageSize()); if (beanFilter != null) page.setFilter(beanFilter); // get initial page and wrap data in container paginator.firstPage(); getTable().addItemClickListener(this); this.setSizeUndefined(); } /** * {@inheritDoc} */ public void pageChanged(PageChangedEvent event) { if (log.isDebugEnabled()) log.debug("handling page change event [" + event.toString() + "]"); if (autoResize) getTable().setPageLength(page.getPageSize()); loadPage(); } /** * Load models from page and add to internal bean item container */ @SuppressWarnings("unchecked") protected void loadPage() { Container container = getContainer(); Class<T> entityClass = getEntityClass(); if (this.page.getData() != null && this.page.getData().size() > 0) { if (container == null) { Class<T> beanClass = (Class<T>) (entityClass != null ? entityClass : this.page.getData().get(0).getClass()); container = createBeanContainer(beanClass, this.page.getData()); getTable().setContainerDataSource(container); setContainer(container); } else { container.removeAllItems(); addBeansFromPage(container); } } else { if (container != null) container.removeAllItems(); } paginator.refresh(); } /** * @param container */ protected void addBeansFromPage(Container container) { ReflectionUtils.invokeMethod(ClassUtils.getMethod(container.getClass(), "addAll", Collection.class), container, page.getData()); } /** * Refresh table */ @Override public void refresh() { this.paginator.setPage(page.getPage()); if (this.filterForm != null) this.filterForm.refresh(); } @Override public VaadinView<T> getEditorView() { VaadinView<T> view = super.getEditorView(); if (view != null && this.propagateService) view.setPersistentService(service); return view; } public void filter() { if (this.filterForm != null) { filterForm.update(); if (!filterForm.validateView()) { Notification.show(filterForm.getErrorMessage(), Notification.Type.ERROR_MESSAGE); } } firstPage(); } /** * @param selected */ @Override public void delete(Collection<?> selected) { try { List<T> beans = new ArrayList<T>(); for (Object id : selected) { beans.add(getBean(getContainer().getItem(id))); } this.service.delete(beans); } catch(DataAccessException dae) { Notification.show("Error", getMessage("PageableTable.deleteError"), Type.ERROR_MESSAGE); } } /** * {@inheritDoc} */ public void containerItemSetChange(ItemSetChangeEvent event) { this.paginator.refresh(); } public ConfigurableTable getTable() { return (ConfigurableTable) super.getTable(); } public void setTable(ConfigurableTable table) { super.setTable(table); } public VaadinPaginator<T> getPaginator() { return paginator; } public void setPaginator(VaadinPaginator<T> paginator) { this.paginator = paginator; } /** * @return the filter Object */ public Object getFilter() { return page.getFilter(); } /** * @param filter */ public void setFilter(Object filter) { page.setFilter(filter); } /** * @return the autoResize */ public boolean isAutoResize() { return autoResize; } /** * @param autoResize the autoResize to set */ public void setAutoResize(boolean autoResize) { this.autoResize = autoResize; } /** * @return the autoCreateEditor */ public boolean isAutoCreateEditor() { return autoCreateEditor; } /** * @param autoCreateEditor the autoCreateEditor to set */ public void setAutoCreateEditor(boolean autoCreateEditor) { this.autoCreateEditor = autoCreateEditor; } /** * Sort using page requests */ class PageSorter implements TableSorter, Serializable { public void sort(Object[] propertyId, boolean[] ascending) { Column c = getTable().getColumn(propertyId[0].toString()); if (c != null && c.isSortable()) { page.setSortName(c.getSortPropertyName()); page.setOrder(ascending[0] ? Page.Order.ASC : Page.Order.DESC); paginator.firstPage(); } } } /** * @return the beanFilter */ public Filter getBeanFilter() { return beanFilter; } /** * @param beanFilter the beanFilter to set */ public void setBeanFilter(Filter beanFilter) { this.beanFilter = beanFilter; } /** * @return the filterEditor */ public String getFilterEditor() { return filterEditor; } /** * @param filterEditor the filterEditor to set */ public void setFilterEditor(String filterEditor) { this.filterEditor = filterEditor; } /** * @return the filterForm */ public VaadinView<Filter> getFilterForm() { return filterForm; } /** * @param filterForm the filterForm to set */ public void setFilterForm(VaadinView<Filter> filterForm) { this.filterForm = filterForm; } /** * {@inheritDoc} */ public void windowClose(CloseEvent e) { if (((FormDialog) e.getWindow()).isDirty()) loadPage(); } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * Go to first page */ public void firstPage() { if (paginator != null) paginator.firstPage(); } /** * @return * @see org.jdal.dao.Page#getSortName() */ public String getSortName() { return page.getSortName(); } /** * @param sortName * @see org.jdal.dao.Page#setSortName(java.lang.String) */ public void setSortName(String sortName) { page.setSortName(sortName); } /** * @return * @see org.jdal.dao.Page#getOrder() */ public Order getOrder() { return page.getOrder(); } /** * @param order * @see org.jdal.dao.Page#setOrder(org.jdal.dao.Page.Order) */ public void setOrder(Order order) { page.setOrder(order); } /** * @return * @see org.jdal.dao.Page#getPageSize() */ public int getPageSize() { return page.getPageSize(); } /** * @param pageSize * @see org.jdal.dao.Page#setPageSize(int) */ public void setPageSize(int pageSize) { page.setPageSize(pageSize); } public Dao<T, ?extends Serializable> getService() { return service; } public void setService(Dao<T, ?extends Serializable> service) { this.service = service; this.page.setPageableDataSource(service); } public boolean isPropagateService() { return propagateService; } public void setPropagateService(boolean propagateService) { this.propagateService = propagateService; } }