From 87e64d5af9cc1dc2a8d79be6227661b64b2077b5 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Tue, 1 Jul 2014 16:56:03 +0300 Subject: [PATCH] Adds key-related helper methods to Renderers. (#13334) Change-Id: Ic7b1ece8b88126323acc2e216acdebe636091b98 --- .../client/ui/grid/EscalatorUpdater.java | 10 ++- .../vaadin/client/ui/grid/GridConnector.java | 15 ++++ .../renderers/AbstractRendererConnector.java | 22 ++++++ .../vaadin/data/RpcDataProviderExtension.java | 15 +++- .../{renderers => }/AbstractRenderer.java | 25 +++++- .../com/vaadin/ui/components/grid/Grid.java | 17 ++-- .../grid/renderers/DateRenderer.java | 2 + .../grid/renderers/HtmlRenderer.java | 2 + .../grid/renderers/NumberRenderer.java | 2 + .../grid/renderers/TextRenderer.java | 2 + .../tests/components/grid/CustomRenderer.java | 22 +++++- .../components/grid/CustomRendererTest.java | 20 +++++ .../components/grid/IntArrayRenderer.java | 2 +- .../components/grid/RowAwareRenderer.java | 41 ++++++++++ .../grid/RowAwareRendererConnector.java | 78 +++++++++++++++++++ 15 files changed, 256 insertions(+), 19 deletions(-) rename server/src/com/vaadin/ui/components/grid/{renderers => }/AbstractRenderer.java (72%) create mode 100644 uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java diff --git a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java index bfe0ba8bcc..481ddf707e 100644 --- a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java +++ b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java @@ -23,6 +23,9 @@ package com.vaadin.client.ui.grid; *

* The updater is responsible for internally handling all remote communication, * should the displayed data need to be fetched remotely. + *

+ * 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 { * Note: 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. *

* 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. * Note: You should not store nor reuse this reference. * @param cellsToUpdate - * A collection of cells which need to be updated. Note: + * A collection of cells that need to be updated. Note: * You should neither store nor reuse the reference to the * iterable, nor to the individual cells. */ diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index daf938a784..9873ca3d2f 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -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; + } } diff --git a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java index b57b674292..e7cbd5bcd5 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java @@ -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 extends protected void extend(ServerConnector target) { // NOOP } + + /** + * Gets the row key for a row index. + *

+ * 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."); + } + } } diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index fd1ca6b9e8..9768950621 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -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. + *

+ * 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/renderers/AbstractRenderer.java b/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java similarity index 72% rename from server/src/com/vaadin/ui/components/grid/renderers/AbstractRenderer.java rename to server/src/com/vaadin/ui/components/grid/AbstractRenderer.java index d5631c6b60..2f0a7e7ebb 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/AbstractRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java @@ -13,12 +13,10 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.ui.components.grid.renderers; +package com.vaadin.ui.components.grid; 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. @@ -66,4 +64,25 @@ public abstract class AbstractRenderer extends AbstractExtension implements public Class getPresentationType() { return presentationType; } + + /** + * Gets the item id for a row key. + *

+ * 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"); + } + } } diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index d20e4efe8b..287bd1ddfd 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -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 keys = keyMapper().getKeys(getSelectedRows()); + List keys = getKeyMapper().getKeys(getSelectedRows()); boolean markAsDirty = true; @@ -259,7 +259,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { @Override public void selectionChange(List selection) { final HashSet newSelection = new HashSet( - keyMapper().getItemIds(selection)); + getKeyMapper().getItemIds(selection)); final HashSet oldSelection = new HashSet( getSelectedRows()); @@ -1062,10 +1062,13 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { } /** - * A shortcut for - * {@link #datasourceExtension}.{@link com.vaadin.data.RpcDataProviderExtension#getKeyMapper() getKeyMapper()} + * 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/DateRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java index 8c062252f2..e7280f76aa 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java @@ -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. * diff --git a/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java index bf5024159f..9c1fbf51d8 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java @@ -15,6 +15,8 @@ */ package com.vaadin.ui.components.grid.renderers; +import com.vaadin.ui.components.grid.AbstractRenderer; + /** * A renderer for presenting HTML content. * diff --git a/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java index bdfe23c366..d071e592ba 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java @@ -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. * diff --git a/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java index e375d5913b..cdef4e17c8 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java @@ -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. * diff --git a/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java b/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java index 7e079e69b7..9ac1a03df3 100644 --- a/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java +++ b/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java @@ -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 property = item.getItemProperty(INT_ARRAY_PROPERTY); - property.setValue(new int[] { 1, 1, 2, 3, 5, 8, 13 }); + Property 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 diff --git a/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java b/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java index 1827f66777..571a929c7e 100644 --- a/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java @@ -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 elements = $(GridElement.class).all(); return elements.get(0); } + + private LabelElement findDebugLabel() { + return $(LabelElement.class).id(CustomRenderer.DEBUG_LABEL_ID); + } } diff --git a/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java b/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java index 9ebae4587d..142c370e13 100644 --- a/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java +++ b/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java @@ -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 { 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 index 0000000000..f55f5f064c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java @@ -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 { + 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 index 0000000000..c82c6c9a18 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java @@ -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 { + public interface RowAwareRendererRpc extends ServerRpc { + void clicky(String key); + } + + public class RowAwareRenderer extends ComplexRenderer { + + @Override + public Collection 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 getType() { + return Void.class; + } + + @Override + protected Renderer createRenderer() { + return new RowAwareRenderer(); + } +} -- 2.39.5