org.wicketstuff.QuickGridView Maven / Gradle / Ivy
/**
* Copyright 2012 Vineet Semwal
*
* 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.wicketstuff;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.markup.repeater.IItemFactory;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.markup.repeater.data.GridView;
import org.apache.wicket.markup.repeater.data.IDataProvider;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.lang.Args;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* it renders items in rows and columns in table/grid format(same as GridView).it also lets you add and remove rows in ajax cases
* without the need to repaint parent(adding parent to AjaxRequestTarget causes re-rendering of whole repeater)
*
* the preferred way to use QuickGridView is with boundaries ie. two components, one placed before and one placed
* after quickview in markup ,together they determine start and end of quickview
*
* @author Vineet Semwal
*/
public abstract class QuickGridView extends QuickViewBase {
/**
* @param id component id
* @param dataProvider data provider
*/
public QuickGridView(String id, IDataProvider dataProvider, IQuickReuseStrategy reuseStrategy) {
super(id, dataProvider, reuseStrategy);
}
/**
* @param id component id
* @param dataProvider data provider
*/
public QuickGridView(String id, IDataProvider dataProvider) {
super(id, dataProvider, new DefaultQuickReuseStrategy());
}
/**
* @param id component id
* @param dataProvider data provider
*/
public QuickGridView(String id, IDataProvider dataProvider, IQuickReuseStrategy reuseStrategy, Component start, Component end) {
super(id, dataProvider, reuseStrategy, start, end);
}
/**
* @param id component id
* @param dataProvider data provider
*/
public QuickGridView(String id, IDataProvider dataProvider, Component start, Component end) {
super(id, dataProvider, new DefaultQuickReuseStrategy(), start, end);
}
public static final String COLUMNS_REPEATER_ID = "cols";
private int columns = 1;
public int getColumns() {
return columns;
}
/**
* Sets number of columns
*
* @param cols number of columns
* @return this for chaining
*/
public QuickGridView setColumns(int cols) {
if (cols < 1) {
throw new IllegalArgumentException("columns can't be smaller than 1");
}
if (columns != cols) {
if (isVersioned()) {
addStateChange();
}
columns = cols;
updateItemsPerPage();
}
return this;
}
protected void updateItemsPerPage() {
long items = (long)getRows() *(long) getColumns();
int itemsPerRequest = (items > Integer.MAX_VALUE) ? Integer.MAX_VALUE :(int) items;
setItemsPerRequest(itemsPerRequest);
}
private int rows = Integer.MAX_VALUE;
public int getRows() {
return rows;
}
/**
* Sets number of rows per page
*
* @param rows number of rows
* @return this for chaining
*/
public QuickGridView setRows(int rows) {
if (rows < 1) {
throw new IllegalArgumentException("rows can't be set smaller than 1");
}
if (this.rows != rows) {
if (isVersioned()) {
addStateChange();
}
this.rows = rows;
updateItemsPerPage();
}
return this;
}
@Override
public IItemFactory factory() {
return new IItemFactory() {
@Override
public Item newItem(int index, IModel model) {
return buildCellItem(index, model);
}
};
}
protected final void populate(Item item) {
populate((CellItem) item);
}
protected abstract void populate(CellItem item);
abstract protected void populateEmptyItem(CellItem item);
public QuickGridView addRowAtStart(RowItem rowItem) {
Args.notNull(rowItem, "rowItem can't be null");
initializeAddAtStartStoreIfRequired();
getAddAtStartStore().add(rowItem);
simpleAddRow(rowItem);
Synchronizer synchronizer = getSynchronizer();
if (synchronizer == null) {
return this;
}
String call = getRepeaterUtil().prepend(rowItem, _getParent(), getStart(), getEnd());
synchronizer.prependScript(call);
synchronizer.add(rowItem);
//
//requestHandler not AjaxRequestTarget
//
if (!synchronizer.isRequestHandlerAjaxRequestTarget()) {
synchronizer.submit();
}
return this;
}
public QuickGridView addRow(RowItem rowItem) {
Args.notNull(rowItem, "rowItem can't be null");
simpleAddRow(rowItem);
Synchronizer synchronizer = getSynchronizer();
if (synchronizer == null) {
return this;
}
String script = getRepeaterUtil().append(rowItem, _getParent(), getStart(), getEnd());
synchronizer.prependScript(script);
synchronizer.add(rowItem);
if (!synchronizer.isRequestHandlerAjaxRequestTarget()) {
synchronizer.submit();
}
return this;
}
/**
* adds rows and their corresponding cells
*
* @param iterator data for which rows and their corresponding cells will be added
* @return this
*/
public QuickGridView addRows(Iterator extends T> iterator) {
Iterator> rows = buildRows(iterator);
while (rows.hasNext()) {
addRow(rows.next());
}
return this;
}
public QuickGridView addRowsAtStart(Iterator extends T> iterator) {
Iterator> rows = buildRows(iterator);
while (rows.hasNext()) {
addRowAtStart(rows.next());
}
return this;
}
public void removeRow(RowItem rowItem) {
Args.notNull(rowItem, "rowItem can't be null");
Synchronizer synchronizer = getSynchronizer();
IAddAtStartStore addAtStartStore = getAddAtStartStore();
if (addAtStartStore != null) {
addAtStartStore.remove(rowItem);
}
if (synchronizer == null) {
simpleRemove(rowItem);
return;
}
String call = getRepeaterUtil().removeItem(rowItem, _getParent());
synchronizer.prependScript(call);
//
//if requestHandler not AjaxRequestTarget
//
if (!synchronizer.isRequestHandlerAjaxRequestTarget()) {
synchronizer.submit();
}
simpleRemoveRow(rowItem);
}
/**
* it's a simple add,new item is not drawn just added,no js fired
*
* @param components component to be added
* @return this
*/
public MarkupContainer simpleAddRow(Component... components) {
simpleAdd(components);
return this;
}
/**
* it's a simple remove,the item is just removed from quickview ,no js fired
*
* @param c
* @return this
*/
public MarkupContainer simpleRemoveRow(Component c) {
simpleRemove(c);
return this;
}
public MarkupContainer simpleRemoveAllRows() {
return simpleRemoveAll();
}
/**
* @param index cellindex from where new cell items should be added
* @param iterator data
* @return iterator of RowItem which are created with their corresponding cells attached to them
*/
@Override
protected Iterator- > buildItems(final int index, Iterator extends T> iterator) {
Iterator
> cells = buildCells(index, iterator);
int rowIndex = index / getColumns();
return (Iterator) buildRows(rowIndex, cells);
}
/**
* @param iterator data
* @return iterator of RowItem which are created with their corresponding cells attached to them
*/
public Iterator> buildRows(Iterator extends T> iterator) {
int cellindex = gridSize();
return (Iterator) buildItems(cellindex, iterator);
}
@Override
public void createChildren(Iterator- > itemIterator) {
Iterator
> rows = buildRows(0, (Iterator) itemIterator);
while (rows.hasNext()) {
simpleAddRow(rows.next());
}
}
protected Iterator> buildRows(final int rowIndex, Iterator> iterator) {
List> rowItems = new ArrayList>();
for (int row = rowIndex; iterator.hasNext(); row++) {
RowItem rowItem = buildRowItem(newChildId(), row);
rowItems.add(rowItem);
for (int i = 0; i < getColumns(); i++) {
if (iterator.hasNext()) {
CellItem cell = iterator.next();
rowItem.getRepeater().add(cell);
} else {
CellItem cell = buildEmptyCellItem(newChildId(), i);
rowItem.getRepeater().add(cell);
}
}
}
return rowItems.iterator();
}
protected Iterator> buildCells(final int index, Iterator extends T> iterator) {
List> cells = new ArrayList>();
for (int i = index; iterator.hasNext(); i++) {
T object = iterator.next();
CellItem cell = buildCellItem(newChildId(), i, object);
cells.add(cell);
}
return cells.iterator();
}
@Override
public List- > addItemsForPage(long page) {
long itemsCount=page*getItemsPerRequest();
int startIndex =getRepeaterUtil().safeLongToInt(itemsCount);
Iterator
> newModels = newModels(startIndex, getItemsPerRequest());
Iterator> newIterator = (Iterator) getReuseStrategy().addItems(startIndex, factory(), newModels);
Iterator> rows = buildRows(startIndex / getRows(), newIterator);
List- > items = new ArrayList
- >();
while (rows.hasNext()) {
RowItem
rowItem = rows.next();
addRow(rowItem);
items.add(rowItem);
}
return items;
}
public int gridSize() {
int rows = size();
int grid = rows * getColumns();
return grid;
}
/**
* new rowItem
*
* @param id childid
* @param index index
* @return RowItem
*/
protected RowItem newRowItem(String id, int index) {
RowItem item = new RowItem(id,index, new Model());
return item;
}
/**
* build cell item means the new cellitem is created and then populated with populate(cell)
*
* @param id cell's id
* @param index cell's index
* @param object model object set to the cellitem
* @return CellItem
*/
public CellItem buildCellItem(String id, int index, T object) {
return buildCellItem(id, index, getDataProvider().model(object));
}
protected CellItem buildCellItem(String id, int index, IModel model) {
CellItem cell = newCellItem(id, index, model);
populate(cell);
return cell;
}
/**
* builds cell item by creating new cellitem and then populating by populateEmptyItem(cell)
*
* @return CellItem
*/
public CellItem buildEmptyCellItem(int index) {
return buildEmptyCellItem(newChildId(), index);
}
/**
* builds cell item by creating new cellitem and then populating by populateEmptyItem(cell)
*
* @return CellItem
*/
public CellItem buildEmptyCellItem(String id, int index) {
CellItem cell = newEmptyCellItem(id, index);
populateEmptyItem(cell);
return cell;
}
public RowItem buildRowItem(String id, int index) {
RowItem item = newRowItem(id, index);
RepeatingView rowView = new RepeatingView(COLUMNS_REPEATER_ID);
item.add(rowView);
return item;
}
/**
* build row item
*
* @return new row item
*/
public RowItem buildRowItem() {
return buildRowItem(newChildId(), size());
}
/**
* returns iterator to iterate through rows in the order they are rendered
*
* @return rows iterator
*/
public Iterator> rows() {
return (Iterator) getItems();
}
/**
* returns iterator to iterate through cells in the order they are rendered
*
* @return cells iterator
*/
public Iterator> cells() {
Iterator rows = (Iterator) rows();
return new GridView.ItemsIterator(rows);
}
protected CellItem newCellItem(String id, int index, IModel model) {
return new CellItem(id,index, model);
}
public CellItem buildCellItem(int index, IModel model) {
return buildCellItem(newChildId(), index, model);
}
public CellItem newEmptyCellItem(String id, int index) {
return new CellItem(id, index, new Model(), true);
}
/*
* a rowitem represents one row
*
* @author Vineet Semwal
*
*/
public static class RowItem extends Item {
public RowItem(String id, int index, IModel model) {
super(id, index, model);
setOutputMarkupId(true);
}
/**
* cells repeater
*
* @return repeater
*/
public RepeatingView getRepeater() {
return (RepeatingView) get(COLUMNS_REPEATER_ID);
}
/**
* @return cells iterator
*/
public Iterator cellItems() {
return getRepeater().iterator();
}
}
/**
* a cell item represents one cell of the QuickGridView
*
* @param
* @author Vineet Semwal
*/
public static class CellItem extends Item {
public CellItem(String id, int index, IModel model) {
this(id, index, model, false);
}
public CellItem(String id, int index, IModel model, boolean empty) {
super(id, index, model);
setOutputMarkupId(true);
}
}
}