package org.nocket.component.table; import java.io.Serializable; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import org.apache.wicket.Component; import org.apache.wicket.behavior.AttributeAppender; import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.navigation.paging.IPageable; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.apache.wicket.util.convert.IConverter; import org.nocket.component.table.ajax.DMDAjaxDataTable; import org.nocket.component.table.behavior.ClickAjaxEventBehavior; import org.nocket.component.table.behavior.DblClickAjaxEventBehavior; import org.nocket.component.table.behavior.IRowClickEventAware; import org.nocket.component.table.js.DMDJavaScriptDataTable; /** * Generic panel displaying tables. The tables are sortable. Depending on type * parameter tables can be sorted either via JavaScript in the browser or on the * server (Ajax and non-Ajax are supported). * * @author blaz02 * @author vocke03 * * @param <T> * Model object type following Java-Bean convention. */ @SuppressWarnings("serial") public class GenericDataTablePanel<T extends Serializable> extends Panel implements IPageable, IRowClickEventAware<T> { private static final Logger log = Logger.getLogger(GenericDataTablePanel.class); private DataTable<T, String> dataTable; private Set<T> selected = new HashSet<T>(); private Map<String, Tupel> columnConverter; protected String cssClassName; private int columnCount = 0; private int rowsPerPage; /** * Defines in which direction the table is initially sorted. If the value is * NONE, the table is initially not sorted, assuming that the data is * provided in a reasonable way. However, the user may still change the * sorting by clicking the header cells */ private ColumnSortOrder initialSortOrder; private String initialSortColumn; private GenericDataTableColumnConfigurator<T> columnConfigurator; /** * Constructor for the table panel. * * @param id * Wicket id of the comonent. * @param data * Model with the list of objects, which must be show in the * table. Model objects must follow Java-Bean conventions. * @param config * Various configuration parameters. See class * {@link GenericDataTableConfigurator}. */ public GenericDataTablePanel(String id, IModel<List<T>> data, GenericDataTableConfigurator<T> config) { super(id, data); this.rowsPerPage = config.rowsPerPage; this.columnConverter = new HashMap<String, Tupel>(); this.columnConfigurator = config.getColumnConfigurator(); this.initialSortOrder = config.initialSortOrder; this.initialSortColumn = config.initialSortColumn; List<IColumn<T, String>> columnDefinitions = columnConfigurator.constructColumnDefinitions(this); SortableDataProvider<T, String> provider = newDataProvider(); switch (config.sortType) { case AJAX: DMDAjaxDataTable<T> ajaxDataTable = new DMDAjaxDataTable<T>("table", columnDefinitions, provider, rowsPerPage, config.navigationbarPosition); ajaxDataTable.setRowClickDelegate(this); dataTable = ajaxDataTable; break; case JS: DMDJavaScriptDataTable<T> jsDataTable = new DMDJavaScriptDataTable<T>("table", columnDefinitions, provider, rowsPerPage, config.navigationbarPosition); jsDataTable.setRowClickDelegate(this); dataTable = jsDataTable; break; default: dataTable = new DMDDefaultDataTable<T>("table", columnDefinitions, provider, rowsPerPage, config.navigationbarPosition); break; } if (config.rowItemClass != null) setRowItemClass(config.rowItemClass); add(dataTable); // adds a CSS Class to the table based on the id of the // GenericDataTablePanel instance. addCssClassToTable("gdtp_" + id); setOutputMarkupId(true); } public void htmlizeTableHeaders() { List<? extends IColumn<T, String>> columnDefinitions = dataTable.getColumns(); for (IColumn<T, String> column : columnDefinitions) { Component headerComponent = column.getHeader(LabelHtmlizer.NO_LABEL); if (!headerComponent.getId().equals(LabelHtmlizer.NO_LABEL)) LabelHtmlizer.enableHtml(headerComponent); } } /** * Older constructor which is just around for compatibility reasons. */ @Deprecated public GenericDataTablePanel(String id, IModel<List<T>> data, String[] columns, String[] sortableColumns) { this(id, data, new GenericDataTableConfigurator<T>() .withColumnConfigurator(new GenericDataTableColumnConfigurator<T>(Arrays.asList(columns), Arrays .asList(sortableColumns)))); } @Override protected void onComponentTag(ComponentTag tag) { super.onComponentTag(tag); //Replace table tag with div tag to ensure wicket generating the table INSIDE the elements tag, not besides it! //Thus prevent buggy behaviour when updating this component on AjaxRequestTarget. tag.setName("div"); } public void setRowItemClass(Class clazz) { ((IRowItemSettable) dataTable).setRowItemClass(clazz); } /** * Adds a CSS class to the markup class attribute to enable more precise css * selectors for styling. * * @param className * The css class name which should be added to the table tag. */ public void addCssClassToTable(String className) { cssClassName = className; dataTable.add(new AttributeAppender("class", className).setSeparator(" ")); } /** * Method defines ISortableDataProvider instance for the table. Default * implementation provides entities form the list specified in the * constructor of GenericDataTablePanel. First property of the */ protected SortableDataProvider<T, String> newDataProvider() { SortParam<String> sortParam = null; if (columnConfigurator.getSortable().size() > 0 && getDefaultSortOrder() != ColumnSortOrder.NONE) { String initialSortColumn = getInitialSortColumn(); if (initialSortColumn == null) { initialSortColumn = columnConfigurator.getSortable().get(0); } sortParam = new SortParam<String>(initialSortColumn, (getDefaultSortOrder() == ColumnSortOrder.UP)); } return new SortableGenericDataProvider<T, String>((IModel<List<T>>) getDefaultModel(), sortParam); } protected String getInitialSortColumn() { return initialSortColumn; } protected ColumnSortOrder getDefaultSortOrder() { return initialSortOrder; } /** * Override this method to provide handler for click events. This works for * JavaScript and Ajax tables only. * */ @Override public ClickAjaxEventBehavior<T> newOnClickEvent(IModel<T> model) { return null; } /** * Override this method to provide handler for double-click events. This * works for JavaScript and Ajax tables only. * * @return New instance of DblClickAjaxEventBehavior */ @Override public DblClickAjaxEventBehavior<T> newOnDblClickEvent(IModel<T> model) { return null; } /** * @return Returns set with references to the instances chosen with the * check-box. */ public Set<T> getSelected() { return this.selected; } /* * Delegate methods to IPageable in order to be able to add pager directly * to the GenericDataTablePanel. */ public long getCurrentPage() { return dataTable.getCurrentPage(); } public void setCurrentPage(long page) { dataTable.setCurrentPage(page); } public long getPageCount() { return dataTable.getPageCount(); } public void setConverterForColumn(Class<?> type, String columnName, IConverter<?> converter) { Tupel tupel = new Tupel(); tupel.one = type; tupel.two = converter; this.columnConverter.put(columnName, tupel); } public void setColumnConverter(Map<String, Tupel> columnConverter) { this.columnConverter = columnConverter; } public Map<String, Tupel> getColumnConverter() { return columnConverter; } public void setColumnCount(int columnCount) { this.columnCount = columnCount; } public List<String> getColumns() { return columnConfigurator.getColumns(); } public int getColumnCount() { return columnCount; } public static class Tupel implements Serializable { public Class<?> one; public IConverter<?> two; } public int getRowsPerPage() { return rowsPerPage; } public ColumnSortOrder getInitialSortOrder() { return initialSortOrder; } public void setInitialSortOrder(ColumnSortOrder initialSortOrder) { this.initialSortOrder = initialSortOrder; } }