From 336ec127d432389af33a54a9426e37f2ab3b191b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Gonz=C3=A1lez=20Fern=C3=A1ndez?= Date: Wed, 26 Aug 2009 11:28:22 +0200 Subject: [PATCH] ItEr23S10CUAsignacionGrupoRecursosAPlanificacionItEr22S10: Adding row renderers based on DetailItem columns --- .../ICellForDetailItemRenderer.java | 10 + .../timetracker/OnDetailItemsRowRenderer.java | 105 +++++++++ .../OnDetailItemsRowRendererTest.java | 205 ++++++++++++++++++ 3 files changed, 320 insertions(+) create mode 100644 ganttzk/src/main/java/org/zkoss/ganttz/timetracker/ICellForDetailItemRenderer.java create mode 100644 ganttzk/src/main/java/org/zkoss/ganttz/timetracker/OnDetailItemsRowRenderer.java create mode 100644 ganttzk/src/test/java/org/zkoss/ganttz/timetracker/OnDetailItemsRowRendererTest.java diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/timetracker/ICellForDetailItemRenderer.java b/ganttzk/src/main/java/org/zkoss/ganttz/timetracker/ICellForDetailItemRenderer.java new file mode 100644 index 000000000..65325e9a2 --- /dev/null +++ b/ganttzk/src/main/java/org/zkoss/ganttz/timetracker/ICellForDetailItemRenderer.java @@ -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 { + + Component cellFor(DetailItem item, T data); + +} diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/timetracker/OnDetailItemsRowRenderer.java b/ganttzk/src/main/java/org/zkoss/ganttz/timetracker/OnDetailItemsRowRenderer.java new file mode 100644 index 000000000..fef310e36 --- /dev/null +++ b/ganttzk/src/main/java/org/zkoss/ganttz/timetracker/OnDetailItemsRowRenderer.java @@ -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 implements RowRenderer { + + public static OnDetailItemsRowRenderer create( + ICellForDetailItemRenderer cellRenderer, + Collection detailItems) { + return create(inferGenericType(cellRenderer), cellRenderer, detailItems); + } + + public static OnDetailItemsRowRenderer create(Class type, + ICellForDetailItemRenderer cellRenderer, + Collection detailItems) { + return new OnDetailItemsRowRenderer(type, cellRenderer, detailItems); + } + + private static Class inferGenericType( + ICellForDetailItemRenderer renderer) { + ParameterizedType parametrizedType = findRenderererInterfaceType(renderer); + Type[] actualTypeArguments = parametrizedType.getActualTypeArguments(); + Type type = actualTypeArguments[0]; + if (!isActualType(type)) { + informCannotBeInferred(renderer); + } + return (Class) 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 detailItems; + private final ICellForDetailItemRenderer cellRenderer; + private Class type; + + private OnDetailItemsRowRenderer(Class type, + ICellForDetailItemRenderer cellRenderer, + Collection detailItems) { + Validate.notNull(type); + Validate.notNull(detailItems); + Validate.notNull(cellRenderer); + Validate.noNullElements(detailItems); + this.cellRenderer = cellRenderer; + this.detailItems = new ArrayList(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); + } + } + +} diff --git a/ganttzk/src/test/java/org/zkoss/ganttz/timetracker/OnDetailItemsRowRendererTest.java b/ganttzk/src/test/java/org/zkoss/ganttz/timetracker/OnDetailItemsRowRendererTest.java new file mode 100644 index 000000000..11de14125 --- /dev/null +++ b/ganttzk/src/test/java/org/zkoss/ganttz/timetracker/OnDetailItemsRowRendererTest.java @@ -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 { + + @Override + public Component cellFor(DetailItem item, Data data) { + return null; + } + + } + + private static class CellRendererNotInferable implements + ICellForDetailItemRenderer { + + @Override + public Component cellFor(DetailItem item, T data) { + return null; + } + + } + + private List detailItems; + + private OnDetailItemsRowRenderer rowRenderer; + + private DateTime start; + + private List data; + + private void givenOnDetailItemsRowRenderer( + ICellForDetailItemRenderer cellRenderer) { + if (detailItems == null) { + givenDetailItems(); + } + rowRenderer = OnDetailItemsRowRenderer.create(Data.class, cellRenderer, + detailItems); + } + + private void givenDetailItems() { + detailItems = new ArrayList(); + 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.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()); + } + + @Test(expected = IllegalArgumentException.class) + public void itNeedsTheTypeAsClass() { + OnDetailItemsRowRenderer.create(null, createStub(), + new ArrayList()); + } + + @Test + public void itCanHaveEmptyDetailItems() { + OnDetailItemsRowRenderer.create(Data.class, createStub(), + new ArrayList()); + } + + @Test + public void itCanInferTheGenericType() { + OnDetailItemsRowRenderer.create(new CellRenderer(), + new ArrayList()); + } + + @Test(expected = IllegalArgumentException.class) + public void ifComesFromRawTypeIsNotInferrable() { + OnDetailItemsRowRenderer.create(createStub(), + new ArrayList()); + } + + @Test(expected = IllegalArgumentException.class) + public void ifItNotShowsTheActualTypeIsNotInferrable() { + OnDetailItemsRowRenderer.create(new CellRendererNotInferable(), + new ArrayList()); + } + + @SuppressWarnings("serial") + @Test(expected = IllegalArgumentException.class) + public void noDetailItemCanBeNull() { + OnDetailItemsRowRenderer.create(Data.class, createStub(), + new ArrayList() { + { + add(new DetailItem(300, "bla")); + add(null); + } + }); + } + + @Test(expected = IllegalArgumentException.class) + public void cantRenderObjectsOfOtherType() { + givenOnDetailItemsRowRenderer(createStub()); + rowRenderer.render(new Row(), ""); + } + + private ICellForDetailItemRenderer createStub() { + return createNiceMock(ICellForDetailItemRenderer.class); + } + + @Test + public void theCellRendererIsUsedForEachCell() { + givenData(); + givenDetailItems(); + ICellForDetailItemRenderer mock = expectTheCellRendererIsCalledForEachCell(); + givenOnDetailItemsRowRenderer(mock); + + renderingTheData(); + + verify(mock); + } + + private void renderingTheData() { + for (Data d : data) { + rowRenderer.render(new Row(), d); + } + } + + private ICellForDetailItemRenderer expectTheCellRendererIsCalledForEachCell() { + ICellForDetailItemRenderer 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 mock = createMock(ICellForDetailItemRenderer.class); + Label labelMock = expectTheCreatedLabelIsAddedToTheRow(mock); + givenOnDetailItemsRowRenderer(mock); + + renderingTheData(); + + verify(labelMock); + } + + private Label expectTheCreatedLabelIsAddedToTheRow( + ICellForDetailItemRenderer 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; + } + +}