]> source.dussan.org Git - vaadin-framework.git/commitdiff
Adds key-related helper methods to Renderers. (#13334)
authorHenrik Paul <henrik@vaadin.com>
Tue, 1 Jul 2014 13:56:03 +0000 (16:56 +0300)
committerHenrik Paul <henrik@vaadin.com>
Fri, 4 Jul 2014 14:16:27 +0000 (17:16 +0300)
Change-Id: Ic7b1ece8b88126323acc2e216acdebe636091b98

16 files changed:
client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java
client/src/com/vaadin/client/ui/grid/GridConnector.java
client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java
server/src/com/vaadin/data/RpcDataProviderExtension.java
server/src/com/vaadin/ui/components/grid/AbstractRenderer.java [new file with mode: 0644]
server/src/com/vaadin/ui/components/grid/Grid.java
server/src/com/vaadin/ui/components/grid/renderers/AbstractRenderer.java [deleted file]
server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java
server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java
server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java
server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java
uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java
uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java
uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java
uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java [new file with mode: 0644]

index bfe0ba8bccf5f0351e02db6850ffc18dbb99b716..481ddf707e0653772517784ba7ece42bca7394fe 100644 (file)
@@ -23,6 +23,9 @@ package com.vaadin.client.ui.grid;
  * <p>
  * The updater is responsible for internally handling all remote communication,
  * should the displayed data need to be fetched remotely.
+ * <p>
+ * This has a similar function to {@link Grid Grid's} {@link Renderer Renderers}
+ * , although they operate on different abstraction levels.
  * 
  * @since 7.4
  * @author Vaadin Ltd
@@ -30,6 +33,7 @@ package com.vaadin.client.ui.grid;
  * @see Escalator#getHeader()
  * @see Escalator#getBody()
  * @see Escalator#getFooter()
+ * @see Renderer
  */
 public interface EscalatorUpdater {
 
@@ -75,8 +79,8 @@ public interface EscalatorUpdater {
      * <em>Note:</em> If rendering of cells is deferred (e.g. because
      * asynchronous data retrieval), this method is responsible for explicitly
      * displaying some placeholder data (empty content is valid). Because the
-     * cells (and rows) in an escalator are recycled, failing to reset a cell
-     * will lead to invalid data being displayed in the escalator.
+     * cells (and rows) in an escalator are recycled, failing to reset a cell's
+     * presentation will lead to wrong data being displayed in the escalator.
      * <p>
      * For performance reasons, the escalator will never autonomously clear any
      * data in a cell.
@@ -85,7 +89,7 @@ public interface EscalatorUpdater {
      *            Information about the row that is being updated.
      *            <em>Note:</em> You should not store nor reuse this reference.
      * @param cellsToUpdate
-     *            A collection of cells which need to be updated. <em>Note:</em>
+     *            A collection of cells that need to be updated. <em>Note:</em>
      *            You should neither store nor reuse the reference to the
      *            iterable, nor to the individual cells.
      */
index daf938a7843535ab636a8b3838f86f4906ea7f8d..9873ca3d2f5b92d9704558ae7e9515a2ba2a936d 100644 (file)
@@ -536,4 +536,19 @@ public class GridConnector extends AbstractComponentConnector {
         var model = this.@com.vaadin.client.ui.grid.GridConnector::selectionModel;
         model.@com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel::deselectByHandle(*)(handle);
     }-*/;
+
+    /**
+     * Gets the row key for a row by index.
+     * 
+     * @param index
+     *            the index of the row for which to get the key
+     * @return the key for the row at {@code index}
+     */
+    public String getRowKey(int index) {
+        final JSONObject row = dataSource.getRow(index);
+        final Object key = dataSource.getRowKey(row);
+        assert key instanceof String : "Internal key was not a String but a "
+                + key.getClass().getSimpleName() + " (" + key + ")";
+        return (String) key;
+    }
 }
index b57b67429202278300b697dfa47b19c402502067..e7cbd5bcd553a46dab5b6ac72eca8fcb34736b7f 100644 (file)
@@ -23,6 +23,7 @@ import com.vaadin.client.extensions.AbstractExtensionConnector;
 import com.vaadin.client.metadata.NoDataException;
 import com.vaadin.client.metadata.Type;
 import com.vaadin.client.metadata.TypeData;
+import com.vaadin.client.ui.grid.GridConnector;
 import com.vaadin.client.ui.grid.Renderer;
 
 /**
@@ -121,4 +122,25 @@ public abstract class AbstractRendererConnector<T> extends
     protected void extend(ServerConnector target) {
         // NOOP
     }
+
+    /**
+     * Gets the row key for a row index.
+     * <p>
+     * In case this renderer wants be able to identify a row in such a way that
+     * the server also understands it, the row key is used for that. Rows are
+     * identified by unified keys between the client and the server.
+     * 
+     * @param index
+     *            the row index for which to get the row key
+     * @return the row key for the row at {@code index}
+     */
+    protected String getRowKey(int index) {
+        final ServerConnector parent = getParent();
+        if (parent instanceof GridConnector) {
+            return ((GridConnector) parent).getRowKey(index);
+        } else {
+            throw new IllegalStateException("Renderers can only be used "
+                    + "with a Grid.");
+        }
+    }
 }
index fd1ca6b9e8acf9eb4fd9813c1703917f7ef5e6bb..9768950621c5a85af2bac74184d478fa4e10f0a7 100644 (file)
@@ -185,7 +185,20 @@ public class RpcDataProviderExtension extends AbstractExtension {
             return keys;
         }
 
-        Object getItemId(String key) throws IllegalStateException {
+        /**
+         * Gets the registered item id based on its key.
+         * <p>
+         * A key is used to identify a particular row on both a server and a
+         * client. This method can be used to get the item id for the row key
+         * that the client has sent.
+         * 
+         * @param key
+         *            the row key for which to retrieve an item id
+         * @return the item id corresponding to {@code key}
+         * @throws IllegalStateException
+         *             if the key mapper does not have a record of {@code key} .
+         */
+        public Object getItemId(String key) throws IllegalStateException {
             Object itemId = itemIdToKey.inverse().get(key);
             if (itemId != null) {
                 return itemId;
diff --git a/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java b/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java
new file mode 100644 (file)
index 0000000..2f0a7e7
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ * 
+ * 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 com.vaadin.ui.components.grid;
+
+import com.vaadin.server.AbstractClientConnector;
+import com.vaadin.server.AbstractExtension;
+
+/**
+ * An abstract base class for server-side Grid renderers.
+ * {@link com.vaadin.client.ui.grid.Renderer Grid renderers}. This class
+ * currently extends the AbstractExtension superclass, but this fact should be
+ * regarded as an implementation detail and subject to change in a future major
+ * or minor Vaadin revision.
+ * 
+ * @param <T>
+ *            the type this renderer knows how to present
+ * 
+ * @since 7.4
+ * @author Vaadin Ltd
+ */
+public abstract class AbstractRenderer<T> extends AbstractExtension implements
+        Renderer<T> {
+
+    private final Class<T> presentationType;
+
+    protected AbstractRenderer(Class<T> presentationType) {
+        this.presentationType = presentationType;
+    }
+
+    /**
+     * This method is inherited from AbstractExtension but should never be
+     * called directly with an AbstractRenderer.
+     */
+    @Deprecated
+    @Override
+    protected Class<Grid> getSupportedParentType() {
+        return Grid.class;
+    }
+
+    /**
+     * This method is inherited from AbstractExtension but should never be
+     * called directly with an AbstractRenderer.
+     */
+    @Deprecated
+    @Override
+    protected void extend(AbstractClientConnector target) {
+        super.extend(target);
+    }
+
+    @Override
+    public Class<T> getPresentationType() {
+        return presentationType;
+    }
+
+    /**
+     * Gets the item id for a row key.
+     * <p>
+     * A key is used to identify a particular row on both a server and a client.
+     * This method can be used to get the item id for the row key that the
+     * client has sent.
+     * 
+     * @param key
+     *            the row key for which to retrieve an item id
+     * @return the item id corresponding to {@code key}
+     */
+    protected Object getItemId(String key) {
+        if (getParent() instanceof Grid) {
+            Grid grid = (Grid) getParent();
+            return grid.getKeyMapper().getItemId(key);
+        } else {
+            throw new IllegalStateException(
+                    "Renderers can be used only with Grid");
+        }
+    }
+}
index d20e4efe8b2449d6f92035a8df9088a5aa299f17..287bd1ddfdad4cef607fef5d614ba0279023002f 100644 (file)
@@ -215,14 +215,14 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier {
             @Override
             public void selectionChange(SelectionChangeEvent event) {
                 for (Object removedItemId : event.getRemoved()) {
-                    keyMapper().unpin(removedItemId);
+                    getKeyMapper().unpin(removedItemId);
                 }
 
                 for (Object addedItemId : event.getAdded()) {
-                    keyMapper().pin(addedItemId);
+                    getKeyMapper().pin(addedItemId);
                 }
 
-                List<String> keys = keyMapper().getKeys(getSelectedRows());
+                List<String> keys = getKeyMapper().getKeys(getSelectedRows());
 
                 boolean markAsDirty = true;
 
@@ -259,7 +259,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier {
             @Override
             public void selectionChange(List<String> selection) {
                 final HashSet<Object> newSelection = new HashSet<Object>(
-                        keyMapper().getItemIds(selection));
+                        getKeyMapper().getItemIds(selection));
                 final HashSet<Object> oldSelection = new HashSet<Object>(
                         getSelectedRows());
 
@@ -1062,10 +1062,13 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier {
     }
 
     /**
-     * A shortcut for
-     * <code>{@link #datasourceExtension}.{@link com.vaadin.data.RpcDataProviderExtension#getKeyMapper() getKeyMapper()}</code>
+     * Gets the
+     * {@link com.vaadin.data.RpcDataProviderExtension.DataProviderKeyMapper
+     * DataProviderKeyMapper} being used by the data source.
+     * 
+     * @return the key mapper being used by the data source
      */
-    private DataProviderKeyMapper keyMapper() {
+    DataProviderKeyMapper getKeyMapper() {
         return datasourceExtension.getKeyMapper();
     }
 
diff --git a/server/src/com/vaadin/ui/components/grid/renderers/AbstractRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/AbstractRenderer.java
deleted file mode 100644 (file)
index d5631c6..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2000-2014 Vaadin Ltd.
- * 
- * 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 com.vaadin.ui.components.grid.renderers;
-
-import com.vaadin.server.AbstractClientConnector;
-import com.vaadin.server.AbstractExtension;
-import com.vaadin.ui.components.grid.Grid;
-import com.vaadin.ui.components.grid.Renderer;
-
-/**
- * An abstract base class for server-side Grid renderers.
- * {@link com.vaadin.client.ui.grid.Renderer Grid renderers}. This class
- * currently extends the AbstractExtension superclass, but this fact should be
- * regarded as an implementation detail and subject to change in a future major
- * or minor Vaadin revision.
- * 
- * @param <T>
- *            the type this renderer knows how to present
- * 
- * @since 7.4
- * @author Vaadin Ltd
- */
-public abstract class AbstractRenderer<T> extends AbstractExtension implements
-        Renderer<T> {
-
-    private final Class<T> presentationType;
-
-    protected AbstractRenderer(Class<T> presentationType) {
-        this.presentationType = presentationType;
-    }
-
-    /**
-     * This method is inherited from AbstractExtension but should never be
-     * called directly with an AbstractRenderer.
-     */
-    @Deprecated
-    @Override
-    protected Class<Grid> getSupportedParentType() {
-        return Grid.class;
-    }
-
-    /**
-     * This method is inherited from AbstractExtension but should never be
-     * called directly with an AbstractRenderer.
-     */
-    @Deprecated
-    @Override
-    protected void extend(AbstractClientConnector target) {
-        super.extend(target);
-    }
-
-    @Override
-    public Class<T> getPresentationType() {
-        return presentationType;
-    }
-}
index 8c062252f23498727876776baf3cf57337d03b60..e7280f76aad29b745256255d040232b7829ed48c 100644 (file)
@@ -19,6 +19,8 @@ import java.text.DateFormat;
 import java.util.Date;
 import java.util.Locale;
 
+import com.vaadin.ui.components.grid.AbstractRenderer;
+
 /**
  * A renderer for presenting date values.
  * 
index bf5024159fc0c57b8f9d5d8591576d01d4a65308..9c1fbf51d8f3f7e022d9fc10bdfb0d7c57c2b6e7 100644 (file)
@@ -15,6 +15,8 @@
  */
 package com.vaadin.ui.components.grid.renderers;
 
+import com.vaadin.ui.components.grid.AbstractRenderer;
+
 /**
  * A renderer for presenting HTML content.
  * 
index bdfe23c36694e571b7f63851661d42f37a37ab95..d071e592ba345cbde4e9e4e9e8740607dc2fb577 100644 (file)
@@ -18,6 +18,8 @@ package com.vaadin.ui.components.grid.renderers;
 import java.text.DecimalFormat;
 import java.util.Locale;
 
+import com.vaadin.ui.components.grid.AbstractRenderer;
+
 /**
  * A renderer for presenting number values.
  * 
index e375d5913be70756e32360eff8b22eeed33a1cd6..cdef4e17c8ac92444b0afe31c19cdf5dd9fdf93c 100644 (file)
@@ -15,6 +15,8 @@
  */
 package com.vaadin.ui.components.grid.renderers;
 
+import com.vaadin.ui.components.grid.AbstractRenderer;
+
 /**
  * A renderer for presenting simple plain-text string values.
  * 
index 7e079e69b7b3c55bd0374d7d9c1f956b1f897dd9..9ac1a03df36994d79b3f618ebded03ad7db71668 100644 (file)
@@ -22,28 +22,42 @@ import com.vaadin.data.util.IndexedContainer;
 import com.vaadin.server.VaadinRequest;
 import com.vaadin.tests.components.AbstractTestUI;
 import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.ui.Label;
 import com.vaadin.ui.components.grid.Grid;
 
 @Widgetset(TestingWidgetSet.NAME)
 public class CustomRenderer extends AbstractTestUI {
 
     private static final Object INT_ARRAY_PROPERTY = "int array";
+    private static final Object VOID_PROPERTY = "void";
+
+    static final Object ITEM_ID = "itemId1";
+    static final String DEBUG_LABEL_ID = "debuglabel";
+    static final String INIT_DEBUG_LABEL_CAPTION = "Debug label placeholder";
 
     @Override
     protected void setup(VaadinRequest request) {
         IndexedContainer container = new IndexedContainer();
         container.addContainerProperty(INT_ARRAY_PROPERTY, int[].class,
                 new int[] {});
+        container.addContainerProperty(VOID_PROPERTY, Void.class, null);
+
+        Item item = container.addItem(ITEM_ID);
 
-        Object itemId = new Object();
-        Item item = container.addItem(itemId);
         @SuppressWarnings("unchecked")
-        Property<int[]> property = item.getItemProperty(INT_ARRAY_PROPERTY);
-        property.setValue(new int[] { 1, 1, 2, 3, 5, 8, 13 });
+        Property<int[]> propertyIntArray = item
+                .getItemProperty(INT_ARRAY_PROPERTY);
+        propertyIntArray.setValue(new int[] { 1, 1, 2, 3, 5, 8, 13 });
+
+        Label debugLabel = new Label(INIT_DEBUG_LABEL_CAPTION);
+        debugLabel.setId(DEBUG_LABEL_ID);
 
         Grid grid = new Grid(container);
         grid.getColumn(INT_ARRAY_PROPERTY).setRenderer(new IntArrayRenderer());
+        grid.getColumn(VOID_PROPERTY).setRenderer(
+                new RowAwareRenderer(debugLabel));
         addComponent(grid);
+        addComponent(debugLabel);
     }
 
     @Override
index 1827f667778971f5fbf5f184a64adc54d759c3e3..571a929c7e5e8c5a05590109ec69032dbb4317e9 100644 (file)
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.junit.Test;
 
+import com.vaadin.testbench.elements.LabelElement;
 import com.vaadin.tests.annotations.TestCategory;
 import com.vaadin.tests.tb3.MultiBrowserTest;
 
@@ -35,8 +36,27 @@ public class CustomRendererTest extends MultiBrowserTest {
                 .getText());
     }
 
+    @Test
+    public void testRowAwareRenderer() throws Exception {
+        openTestURL();
+
+        GridElement grid = findGrid();
+        assertEquals("Click me!", grid.getCell(0, 1).getText());
+        assertEquals(CustomRenderer.INIT_DEBUG_LABEL_CAPTION, findDebugLabel()
+                .getText());
+
+        grid.getCell(0, 1).click();
+        assertEquals("row: 0, key: 0", grid.getCell(0, 1).getText());
+        assertEquals("key: 0, itemId: " + CustomRenderer.ITEM_ID,
+                findDebugLabel().getText());
+    }
+
     private GridElement findGrid() {
         List<GridElement> elements = $(GridElement.class).all();
         return elements.get(0);
     }
+
+    private LabelElement findDebugLabel() {
+        return $(LabelElement.class).id(CustomRenderer.DEBUG_LABEL_ID);
+    }
 }
index 9ebae4587daf12f7c08b1799c1365e1bf69d14d1..142c370e13a80dced22c2a43e4be82e3631b3c58 100644 (file)
@@ -18,7 +18,7 @@ package com.vaadin.tests.components.grid;
 import org.json.JSONArray;
 import org.json.JSONException;
 
-import com.vaadin.ui.components.grid.renderers.AbstractRenderer;
+import com.vaadin.ui.components.grid.AbstractRenderer;
 
 public class IntArrayRenderer extends AbstractRenderer<int[]> {
     public IntArrayRenderer() {
diff --git a/uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java b/uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java
new file mode 100644 (file)
index 0000000..f55f5f0
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ * 
+ * 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 com.vaadin.tests.components.grid;
+
+import org.json.JSONObject;
+
+import com.vaadin.tests.widgetset.client.grid.RowAwareRendererConnector.RowAwareRendererRpc;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.components.grid.AbstractRenderer;
+
+public class RowAwareRenderer extends AbstractRenderer<Void> {
+    public RowAwareRenderer(final Label debugLabel) {
+        super(Void.class);
+        registerRpc(new RowAwareRendererRpc() {
+            @Override
+            public void clicky(String key) {
+                Object itemId = getItemId(key);
+                debugLabel.setValue("key: " + key + ", itemId: " + itemId);
+            }
+        });
+    }
+
+    @Override
+    public Object encode(Void value) {
+        return JSONObject.NULL;
+    }
+
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java
new file mode 100644 (file)
index 0000000..c82c6c9
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ * 
+ * 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 com.vaadin.tests.widgetset.client.grid;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import com.google.gwt.dom.client.BrowserEvents;
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.user.client.DOM;
+import com.vaadin.client.ui.grid.Cell;
+import com.vaadin.client.ui.grid.FlyweightCell;
+import com.vaadin.client.ui.grid.Renderer;
+import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector;
+import com.vaadin.client.ui.grid.renderers.ComplexRenderer;
+import com.vaadin.shared.communication.ServerRpc;
+import com.vaadin.shared.ui.Connect;
+
+@Connect(com.vaadin.tests.components.grid.RowAwareRenderer.class)
+public class RowAwareRendererConnector extends AbstractRendererConnector<Void> {
+    public interface RowAwareRendererRpc extends ServerRpc {
+        void clicky(String key);
+    }
+
+    public class RowAwareRenderer extends ComplexRenderer<Void> {
+
+        @Override
+        public Collection<String> getConsumedEvents() {
+            return Arrays.asList(BrowserEvents.CLICK);
+        }
+
+        @Override
+        public void init(FlyweightCell cell) {
+            DivElement div = DivElement.as(DOM.createDiv());
+            div.setAttribute("style",
+                    "border: 1px solid red; background: pink;");
+            div.setInnerText("Click me!");
+            cell.getElement().appendChild(div);
+        }
+
+        @Override
+        public void render(FlyweightCell cell, Void data) {
+            // NOOP
+        }
+
+        @Override
+        public void onBrowserEvent(Cell cell, NativeEvent event) {
+            int row = cell.getRow();
+            String key = getRowKey(row);
+            getRpcProxy(RowAwareRendererRpc.class).clicky(key);
+            cell.getElement().setInnerText("row: " + row + ", key: " + key);
+        }
+    }
+
+    @Override
+    protected Class<Void> getType() {
+        return Void.class;
+    }
+
+    @Override
+    protected Renderer<Void> createRenderer() {
+        return new RowAwareRenderer();
+    }
+}