ItEr23S10CUAsignacionGrupoRecursosAPlanificacionItEr22S10: Adding row renderers based on DetailItem columns
This commit is contained in:
parent
fe0d44447a
commit
336ec127d4
3 changed files with 320 additions and 0 deletions
|
|
@ -0,0 +1,10 @@
|
|||
package org.zkoss.ganttz.timetracker;
|
||||
|
||||
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
|
||||
public interface ICellForDetailItemRenderer<T> {
|
||||
|
||||
Component cellFor(DetailItem item, T data);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package org.zkoss.ganttz.timetracker;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zul.Row;
|
||||
import org.zkoss.zul.RowRenderer;
|
||||
|
||||
public class OnDetailItemsRowRenderer<T> implements RowRenderer {
|
||||
|
||||
public static <T> OnDetailItemsRowRenderer<T> create(
|
||||
ICellForDetailItemRenderer<T> cellRenderer,
|
||||
Collection<DetailItem> detailItems) {
|
||||
return create(inferGenericType(cellRenderer), cellRenderer, detailItems);
|
||||
}
|
||||
|
||||
public static <T> OnDetailItemsRowRenderer<T> create(Class<T> type,
|
||||
ICellForDetailItemRenderer<T> cellRenderer,
|
||||
Collection<DetailItem> detailItems) {
|
||||
return new OnDetailItemsRowRenderer<T>(type, cellRenderer, detailItems);
|
||||
}
|
||||
|
||||
private static <T> Class<T> inferGenericType(
|
||||
ICellForDetailItemRenderer<T> renderer) {
|
||||
ParameterizedType parametrizedType = findRenderererInterfaceType(renderer);
|
||||
Type[] actualTypeArguments = parametrizedType.getActualTypeArguments();
|
||||
Type type = actualTypeArguments[0];
|
||||
if (!isActualType(type)) {
|
||||
informCannotBeInferred(renderer);
|
||||
}
|
||||
return (Class<T>) actualTypeArguments[0];
|
||||
}
|
||||
|
||||
private static boolean isActualType(Type t) {
|
||||
return t instanceof Class;
|
||||
}
|
||||
|
||||
private static ParameterizedType findRenderererInterfaceType(
|
||||
ICellForDetailItemRenderer<?> renderer) {
|
||||
Type[] genericInterfaces = renderer.getClass().getGenericInterfaces();
|
||||
for (Type type : genericInterfaces) {
|
||||
if (isTypeForInterface(type, ICellForDetailItemRenderer.class)) {
|
||||
if (type instanceof ParameterizedType) {
|
||||
return (ParameterizedType) type;
|
||||
} else
|
||||
informCannotBeInferred(renderer);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("shouldn't reach here. Uncovered case for "
|
||||
+ renderer);
|
||||
}
|
||||
|
||||
private static boolean isTypeForInterface(Type type,
|
||||
Class<?> interfaceBeingSearched) {
|
||||
if (type instanceof ParameterizedType) {
|
||||
ParameterizedType p = (ParameterizedType) type;
|
||||
Type rawType = p.getRawType();
|
||||
return rawType.equals(interfaceBeingSearched);
|
||||
}
|
||||
return type.equals(interfaceBeingSearched);
|
||||
}
|
||||
|
||||
private static void informCannotBeInferred(
|
||||
ICellForDetailItemRenderer<?> renderer) {
|
||||
throw new IllegalArgumentException(
|
||||
"the generic type cannot be inferred "
|
||||
+ "if actual type parameters are not declared "
|
||||
+ "or implements the raw interface: "
|
||||
+ renderer.getClass().getName());
|
||||
}
|
||||
|
||||
private final List<DetailItem> detailItems;
|
||||
private final ICellForDetailItemRenderer<T> cellRenderer;
|
||||
private Class<T> type;
|
||||
|
||||
private OnDetailItemsRowRenderer(Class<T> type,
|
||||
ICellForDetailItemRenderer<T> cellRenderer,
|
||||
Collection<DetailItem> detailItems) {
|
||||
Validate.notNull(type);
|
||||
Validate.notNull(detailItems);
|
||||
Validate.notNull(cellRenderer);
|
||||
Validate.noNullElements(detailItems);
|
||||
this.cellRenderer = cellRenderer;
|
||||
this.detailItems = new ArrayList<DetailItem>(detailItems);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Row row, Object data) {
|
||||
if (!type.isInstance(data))
|
||||
throw new IllegalArgumentException(data + " is not instance of "
|
||||
+ type);
|
||||
for (DetailItem item : detailItems) {
|
||||
Component child = cellRenderer.cellFor(item, type.cast(data));
|
||||
child.setParent(row);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
package org.zkoss.ganttz.timetracker;
|
||||
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.createNiceMock;
|
||||
import static org.easymock.EasyMock.createStrictMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.isA;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.Period;
|
||||
import org.junit.Test;
|
||||
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zul.Row;
|
||||
import org.zkoss.zul.api.Label;
|
||||
|
||||
public class OnDetailItemsRowRendererTest {
|
||||
|
||||
private static class Data {
|
||||
|
||||
}
|
||||
|
||||
private static class CellRenderer implements
|
||||
ICellForDetailItemRenderer<Data> {
|
||||
|
||||
@Override
|
||||
public Component cellFor(DetailItem item, Data data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class CellRendererNotInferable<T> implements
|
||||
ICellForDetailItemRenderer<T> {
|
||||
|
||||
@Override
|
||||
public Component cellFor(DetailItem item, T data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private List<DetailItem> detailItems;
|
||||
|
||||
private OnDetailItemsRowRenderer<Data> rowRenderer;
|
||||
|
||||
private DateTime start;
|
||||
|
||||
private List<Data> data;
|
||||
|
||||
private void givenOnDetailItemsRowRenderer(
|
||||
ICellForDetailItemRenderer<Data> cellRenderer) {
|
||||
if (detailItems == null) {
|
||||
givenDetailItems();
|
||||
}
|
||||
rowRenderer = OnDetailItemsRowRenderer.create(Data.class, cellRenderer,
|
||||
detailItems);
|
||||
}
|
||||
|
||||
private void givenDetailItems() {
|
||||
detailItems = new ArrayList<DetailItem>();
|
||||
start = new LocalDate(2010, 1, 1).toDateMidnight().toDateTime();
|
||||
DateTime current = start;
|
||||
Period period = Period.months(2);
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
DateTime end = current.plus(period);
|
||||
DetailItem detail = new DetailItem(200, i + "", current, end);
|
||||
current = end;
|
||||
detailItems.add(detail);
|
||||
}
|
||||
}
|
||||
|
||||
private void givenData() {
|
||||
data = new ArrayList<Data>();
|
||||
data.add(new Data());
|
||||
data.add(new Data());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void itNeedsNotNullDetailItems() {
|
||||
OnDetailItemsRowRenderer.create(Data.class, createStub(), null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void itNeedsNotNullCellRenderer() {
|
||||
OnDetailItemsRowRenderer.create(Data.class, null,
|
||||
new ArrayList<DetailItem>());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void itNeedsTheTypeAsClass() {
|
||||
OnDetailItemsRowRenderer.create(null, createStub(),
|
||||
new ArrayList<DetailItem>());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itCanHaveEmptyDetailItems() {
|
||||
OnDetailItemsRowRenderer.create(Data.class, createStub(),
|
||||
new ArrayList<DetailItem>());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itCanInferTheGenericType() {
|
||||
OnDetailItemsRowRenderer.create(new CellRenderer(),
|
||||
new ArrayList<DetailItem>());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void ifComesFromRawTypeIsNotInferrable() {
|
||||
OnDetailItemsRowRenderer.create(createStub(),
|
||||
new ArrayList<DetailItem>());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void ifItNotShowsTheActualTypeIsNotInferrable() {
|
||||
OnDetailItemsRowRenderer.create(new CellRendererNotInferable<Data>(),
|
||||
new ArrayList<DetailItem>());
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void noDetailItemCanBeNull() {
|
||||
OnDetailItemsRowRenderer.create(Data.class, createStub(),
|
||||
new ArrayList<DetailItem>() {
|
||||
{
|
||||
add(new DetailItem(300, "bla"));
|
||||
add(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void cantRenderObjectsOfOtherType() {
|
||||
givenOnDetailItemsRowRenderer(createStub());
|
||||
rowRenderer.render(new Row(), "");
|
||||
}
|
||||
|
||||
private ICellForDetailItemRenderer<Data> createStub() {
|
||||
return createNiceMock(ICellForDetailItemRenderer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theCellRendererIsUsedForEachCell() {
|
||||
givenData();
|
||||
givenDetailItems();
|
||||
ICellForDetailItemRenderer<Data> mock = expectTheCellRendererIsCalledForEachCell();
|
||||
givenOnDetailItemsRowRenderer(mock);
|
||||
|
||||
renderingTheData();
|
||||
|
||||
verify(mock);
|
||||
}
|
||||
|
||||
private void renderingTheData() {
|
||||
for (Data d : data) {
|
||||
rowRenderer.render(new Row(), d);
|
||||
}
|
||||
}
|
||||
|
||||
private ICellForDetailItemRenderer<Data> expectTheCellRendererIsCalledForEachCell() {
|
||||
ICellForDetailItemRenderer<Data> mock = createStrictMock(ICellForDetailItemRenderer.class);
|
||||
Label labelMock = createNiceMock(Label.class);
|
||||
for (Data d : data) {
|
||||
for (DetailItem item : detailItems) {
|
||||
expect(mock.cellFor(item, d)).andReturn(labelMock);
|
||||
}
|
||||
}
|
||||
replay(mock);
|
||||
return mock;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theCreatedComponentsAreAddedToTheParents() {
|
||||
givenData();
|
||||
givenDetailItems();
|
||||
ICellForDetailItemRenderer<Data> mock = createMock(ICellForDetailItemRenderer.class);
|
||||
Label labelMock = expectTheCreatedLabelIsAddedToTheRow(mock);
|
||||
givenOnDetailItemsRowRenderer(mock);
|
||||
|
||||
renderingTheData();
|
||||
|
||||
verify(labelMock);
|
||||
}
|
||||
|
||||
private Label expectTheCreatedLabelIsAddedToTheRow(
|
||||
ICellForDetailItemRenderer<Data> mock) {
|
||||
Label labelMock = createStrictMock(Label.class);
|
||||
for (Data d : data) {
|
||||
for (DetailItem item : detailItems) {
|
||||
expect(mock.cellFor(isA(DetailItem.class), isA(Data.class)))
|
||||
.andReturn(labelMock);
|
||||
labelMock.setParent(isA(Row.class));
|
||||
}
|
||||
}
|
||||
replay(mock, labelMock);
|
||||
return labelMock;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue