package fr.openwide.core.wicket.more.markup.repeater.table;
import java.util.List;
import java.util.Map;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IStyledColumn;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.navigation.paging.IPageableItems;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.IItemReuseStrategy;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.IDataProvider;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.util.lang.Args;
import com.google.common.collect.Lists;
import fr.openwide.core.jpa.more.business.sort.ISort;
import fr.openwide.core.wicket.behavior.ClassAttributeAppender;
import fr.openwide.core.wicket.more.condition.Condition;
import fr.openwide.core.wicket.more.markup.repeater.sequence.ISequenceProvider;
import fr.openwide.core.wicket.more.markup.repeater.sequence.SequenceGridView;
import fr.openwide.core.wicket.more.util.model.Detachables;
import fr.openwide.core.wicket.more.util.model.SequenceProviders;
/**
* A re-implementation of DataTable that accepts ISequenceProvider instead of IDataProvider.
* <p>Also, it allows dynamic hiding of columns based on {@link Condition}s.
*/
public class CoreDataTable<T, S extends ISort<?>> extends Panel implements IPageableItems {
private static final long serialVersionUID = 1L;
private final Map<IColumn<T, S>, Condition> columnToConditionMap;
private final List<IColumn<T, S>> displayedColumns;
private final SequenceGridView<T> gridView;
private final WebMarkupContainer body;
private final CoreToolbarsContainer topToolbars;
private final CoreToolbarsContainer bodyBottomToolbars;
private final CoreToolbarsContainer bottomToolbars;
private int toolbarIdCounter = 0;
private MarkupContainer componentToRefresh;
public CoreDataTable(String id, Map<IColumn<T, S>, Condition> columns, IDataProvider<T> dataProvider, long rowsPerPage) {
this(id, columns, SequenceProviders.forDataProvider(dataProvider), rowsPerPage);
}
public CoreDataTable(String id, Map<IColumn<T, S>, Condition> columns, ISequenceProvider<T> sequenceProvider, long rowsPerPage) {
super(id);
this.columnToConditionMap = columns;
this.displayedColumns = Lists.newArrayList();
body = newBodyContainer("body");
add(body);
gridView = newGridView("rows", displayedColumns, sequenceProvider);
gridView.setItemsPerPage(rowsPerPage);
body.add(gridView);
bodyBottomToolbars = new CoreToolbarsContainer("bodyBottomToolbars");
body.add(bodyBottomToolbars);
topToolbars = new CoreToolbarsContainer("topToolbars");
bottomToolbars = new CoreToolbarsContainer("bottomToolbars");
add(topToolbars, bottomToolbars);
setComponentToRefresh(this);
}
@Override
protected void onDetach() {
super.onDetach();
Detachables.detach(columnToConditionMap);
}
@Override
protected void onConfigure() {
super.onConfigure();
// Update the displayed columns
displayedColumns.clear();
for (Map.Entry<IColumn<T, S>, Condition> entry : columnToConditionMap.entrySet()) {
Condition condition = entry.getValue();
if (condition == null || condition.applies()) {
IColumn<T, S> column = entry.getKey();
displayedColumns.add(column);
}
}
}
@Override
public long getCurrentPage() {
return gridView.getCurrentPage();
}
@Override
public void setCurrentPage(long page) {
gridView.setCurrentPage(page);
onPageChanged();
}
protected void onPageChanged() {
// No-op by default
}
@Override
public long getPageCount() {
return gridView.getPageCount();
}
@Override
public long getItemCount() {
return gridView.getItemCount();
}
@Override
public long getItemsPerPage() {
return gridView.getItemsPerPage();
}
public long getRowCount() {
return gridView.getRowCount();
}
@Override
public void setItemsPerPage(long itemsPerPage) {
gridView.setItemsPerPage(itemsPerPage);
}
public final CoreDataTable<T, S> setItemReuseStrategy(final IItemReuseStrategy strategy) {
gridView.setItemReuseStrategy(strategy);
return this;
}
public ISequenceProvider<T> getSequenceProvider() {
return gridView.getSequenceProvider();
}
/**
* @see AbstractCoreToolbar
*/
String newToolbarId()
{
toolbarIdCounter++;
return String.valueOf(toolbarIdCounter).intern();
}
private void addToolbar(final AbstractCoreToolbar toolbar, final CoreToolbarsContainer container) {
Args.notNull(toolbar, "toolbar");
container.getRepeatingView().add(toolbar);
}
public void addTopToolbar(final AbstractCoreToolbar toolbar) {
addToolbar(toolbar, topToolbars);
}
public void addBodyBottomToolbar(final AbstractCoreToolbar toolbar) {
Args.notNull(toolbar, "toolbar");
bodyBottomToolbars.getRepeatingView().add(toolbar);
}
public void addBottomToolbar(final AbstractCoreToolbar toolbar) {
addToolbar(toolbar, bottomToolbars);
}
protected WebMarkupContainer newBodyContainer(final String id) {
return new WebMarkupContainer(id);
}
protected SequenceGridView<T> newGridView(String id, List<? extends IColumn<T, S>> columns,
ISequenceProvider<T> sequenceProvider) {
return new DefaultGridView(id, columns, sequenceProvider);
}
protected Item<IColumn<T, S>> newCellItem(String id, int index, IModel<IColumn<T, S>> model) {
Item<IColumn<T, S>> cellItem = new Item<>(id, index, model);
cellItem.setOutputMarkupId(true);
return cellItem;
}
protected Item<T> newRowItem(String id, int index, IModel<T> model) {
Item<T> rowItem = new Item<>(id, index, model);
rowItem.setOutputMarkupId(true);
return rowItem;
}
public Map<IColumn<T, S>, Condition> getColumnToConditionMap() {
return columnToConditionMap;
}
public List<IColumn<T, S>> getDisplayedColumns() {
return displayedColumns;
}
public MarkupContainer getComponentToRefresh() {
return componentToRefresh;
}
public void setComponentToRefresh(MarkupContainer component) {
Args.isTrue(
component == this || component.contains(this, true),
"The component to refresh in stead of a DataTable must contain the DataTable. {} does not contain {}",
component, this
);
this.componentToRefresh = component;
this.componentToRefresh.setOutputMarkupId(true);
}
protected class DefaultGridView extends SequenceGridView<T> {
private static final long serialVersionUID = 1L;
public DefaultGridView(String id, List<? extends IColumn<T, S>> displayedColumns, ISequenceProvider<T> sequenceProvider) {
super(id, displayedColumns, sequenceProvider);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
protected Item newCellItem(final String id, final int index, final IModel model) {
Item item = CoreDataTable.this.newCellItem(id, index, model);
final ICellPopulator<T> column = internalGetPopulators().get(index);
if (column instanceof IStyledColumn) {
item.add(new ClassAttributeAppender(new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
@Override
public String getObject() {
return ((IStyledColumn<T, S>) column).getCssClass();
}
}));
}
return item;
}
@Override
protected Item<T> newRowItem(final String id, final int index, final IModel<T> model) {
return CoreDataTable.this.newRowItem(id, index, model);
}
}
}