From 5b3c9bc4ebfcb2837b07327b81831e81db2deccc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Johannes=20Dahlstr=C3=B6m?= Date: Thu, 25 Sep 2014 17:18:08 +0300 Subject: [PATCH] Implement ButtonRenderer (#13334) Change-Id: Id7c6f3cf85f8e75905e86b55edbc1b8782780996 --- .../src/com/vaadin/client/ui/grid/Grid.java | 13 ++ .../ui/grid/renderers/ButtonRenderer.java | 150 ++++++++++++++++++ .../renderers/ButtonRendererConnector.java | 61 +++++++ .../ui/grid/renderers/WidgetRenderer.java | 30 +++- .../grid/renderers/ButtonRenderer.java | 129 +++++++++++++++ .../ui/grid/renderers/RendererClickRpc.java | 30 ++++ .../components/grid/WidgetRenderers.java | 24 ++- .../components/grid/WidgetRenderersTest.java | 23 ++- 8 files changed, 454 insertions(+), 6 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/renderers/ButtonRenderer.java create mode 100644 client/src/com/vaadin/client/ui/grid/renderers/ButtonRendererConnector.java create mode 100644 server/src/com/vaadin/ui/components/grid/renderers/ButtonRenderer.java create mode 100644 shared/src/com/vaadin/shared/ui/grid/renderers/RendererClickRpc.java diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 7be14cb068..074d795946 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -2197,6 +2197,19 @@ public class Grid extends ResizeComposite implements } } + /** + * Returns the cell the given element belongs to. For internal use only. + * + * @param e + * a cell element or the descendant of one + * @return the cell or null if no such cell + */ + public Cell findCell(Element e) { + RowContainer container = escalator.findRowContainer(e); + return container != null ? container.getCell(e) : null; + + } + private boolean handleEditorRowEvent(Event event, RowContainer container, Cell cell) { if (editorRow.getState() != State.INACTIVE) { diff --git a/client/src/com/vaadin/client/ui/grid/renderers/ButtonRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/ButtonRenderer.java new file mode 100644 index 0000000000..90812bfba1 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/renderers/ButtonRenderer.java @@ -0,0 +1,150 @@ +/* + * 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.client.ui.grid.renderers; + +import com.google.gwt.core.shared.GWT; +import com.google.gwt.dom.client.BrowserEvents; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DomEvent; +import com.google.gwt.event.dom.client.MouseEvent; +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.HandlerManager; +import com.google.gwt.user.client.ui.Button; +import com.google.web.bindery.event.shared.HandlerRegistration; +import com.vaadin.client.Util; +import com.vaadin.client.ui.grid.Cell; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Grid; + +/** + * A Renderer that displays buttons with textual captions. The values of the + * corresponding column are used as the captions. Click handlers can be added to + * the renderer, invoked when any of the rendered buttons is clicked. + * + * @param + * the row type + * + * @since + * @author Vaadin Ltd + */ +public class ButtonRenderer extends WidgetRenderer implements + ClickHandler { + + /** + * A handler for {@link RendererClickEvent renderer click events}. + * + * @see {@link ButtonRenderer#addClickHandler(RendererClickHandler)} + */ + public interface RendererClickHandler extends EventHandler { + + /** + * Called when a rendered button is clicked. + * + * @param event + * the event representing the click + */ + void onClick(RendererClickEvent event); + } + + /** + * An event fired when a button rendered by a ButtonRenderer is clicked. + */ + @SuppressWarnings("rawtypes") + public static class RendererClickEvent extends + MouseEvent { + + @SuppressWarnings("unchecked") + private static final Type TYPE = new Type( + BrowserEvents.CLICK, new RendererClickEvent()); + + private Cell cell; + + private T row; + + private RendererClickEvent() { + } + + /** + * Returns the cell of the clicked button. + * + * @return the cell + */ + public Cell getCell() { + return cell; + } + + /** + * Returns the data object corresponding to the row of the clicked + * button. + * + * @return the row data object + */ + public T getRow() { + return row; + } + + @Override + public Type getAssociatedType() { + return TYPE; + } + + @Override + @SuppressWarnings("unchecked") + protected void dispatch(RendererClickHandler handler) { + cell = WidgetRenderer.getCell(getNativeEvent()); + assert cell != null; + Grid grid = Util.findWidget(cell.getElement(), Grid.class); + row = grid.getDataSource().getRow(cell.getRow()); + handler.onClick(this); + } + } + + private HandlerManager handlerManager; + + @Override + public Button createWidget() { + Button b = GWT.create(Button.class); + b.addClickHandler(this); + return b; + } + + @Override + public void render(FlyweightCell cell, String text, Button button) { + button.setText(text); + } + + /** + * Adds a click handler to this button renderer. The handler is invoked + * every time one of the buttons rendered by this renderer is clicked. + * + * @param handler + * the click handler to be added + */ + public HandlerRegistration addClickHandler(RendererClickHandler handler) { + if (handlerManager == null) { + handlerManager = new HandlerManager(this); + } + return handlerManager.addHandler(RendererClickEvent.TYPE, handler); + } + + @Override + public void onClick(ClickEvent event) { + if (handlerManager != null) { + DomEvent.fireNativeEvent(event.getNativeEvent(), handlerManager); + } + } +} diff --git a/client/src/com/vaadin/client/ui/grid/renderers/ButtonRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/ButtonRendererConnector.java new file mode 100644 index 0000000000..899975b0eb --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/renderers/ButtonRendererConnector.java @@ -0,0 +1,61 @@ +/* + * 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.client.ui.grid.renderers; + +import com.google.gwt.json.client.JSONObject; +import com.google.web.bindery.event.shared.HandlerRegistration; +import com.vaadin.client.MouseEventDetailsBuilder; +import com.vaadin.client.ui.grid.renderers.ButtonRenderer.RendererClickEvent; +import com.vaadin.client.ui.grid.renderers.ButtonRenderer.RendererClickHandler; +import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.grid.renderers.RendererClickRpc; + +/** + * A connector for {@link ButtonRenderer}. + * + * @since + * @author Vaadin Ltd + */ +@Connect(com.vaadin.ui.components.grid.renderers.ButtonRenderer.class) +public class ButtonRendererConnector extends AbstractRendererConnector + implements RendererClickHandler { + + HandlerRegistration clickRegistration; + + @Override + protected void init() { + clickRegistration = getRenderer().addClickHandler(this); + } + + @Override + public void onUnregister() { + clickRegistration.removeHandler(); + } + + @Override + public ButtonRenderer getRenderer() { + return (ButtonRenderer) super.getRenderer(); + } + + @Override + public void onClick(RendererClickEvent event) { + getRpcProxy(RendererClickRpc.class).click( + event.getCell().getRow(), + event.getCell().getColumn(), + MouseEventDetailsBuilder.buildMouseEventDetails(event + .getNativeEvent())); + } +} diff --git a/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java index 9fcd9c906e..5d07e0929b 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java @@ -15,9 +15,14 @@ */ package com.vaadin.client.ui.grid.renderers; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.EventTarget; +import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.Util; +import com.vaadin.client.ui.grid.Cell; import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Grid; /** * A renderer for rendering widgets into cells. @@ -48,7 +53,7 @@ public abstract class WidgetRenderer extends @Override public void render(FlyweightCell cell, T data) { - W w = Util.findWidget(cell.getElement().getFirstChildElement(), null); + W w = getWidget(cell.getElement()); assert w != null : "Widget not found in cell (" + cell.getColumn() + "," + cell.getRow() + ")"; render(cell, data, w); @@ -69,4 +74,27 @@ public abstract class WidgetRenderer extends */ public abstract void render(FlyweightCell cell, T data, W widget); + protected W getWidget(Element e) { + return Util.findWidget(e.getFirstChildElement(), null); + } + + /** + * Returns the cell instance corresponding to the element that the given + * event originates from. If the event does not originate from a grid cell, + * returns null. + * + * @param event + * the event + * @return the cell or null if no such cell + */ + protected static Cell getCell(NativeEvent event) { + EventTarget target = event.getEventTarget(); + if (!Element.is(target)) { + return null; + } + + Element elem = Element.as(target); + Grid grid = Util.findWidget(elem, Grid.class); + return grid.findCell(elem); + } } diff --git a/server/src/com/vaadin/ui/components/grid/renderers/ButtonRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/ButtonRenderer.java new file mode 100644 index 0000000000..de63449f81 --- /dev/null +++ b/server/src/com/vaadin/ui/components/grid/renderers/ButtonRenderer.java @@ -0,0 +1,129 @@ +/* + * 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 java.lang.reflect.Method; + +import com.vaadin.event.ConnectorEventListener; +import com.vaadin.event.MouseEvents.ClickEvent; +import com.vaadin.shared.MouseEventDetails; +import com.vaadin.shared.ui.grid.renderers.RendererClickRpc; +import com.vaadin.ui.components.grid.AbstractRenderer; +import com.vaadin.ui.components.grid.Grid; +import com.vaadin.util.ReflectTools; + +/** + * A Renderer that displays a button with a textual caption. The value of the + * corresponding property is used as the caption. Click listeners can be added + * to the renderer, invoked when any of the rendered buttons is clicked. + * + * @since + * @author Vaadin Ltd + */ +public class ButtonRenderer extends AbstractRenderer { + + /** + * An interface for listening to {@link RendererClickEvent renderer click + * events}. + * + * @see {@link ButtonRenderer#addClickListener(RendererClickListener)} + */ + public interface RendererClickListener extends ConnectorEventListener { + + static final Method CLICK_METHOD = ReflectTools.findMethod( + RendererClickListener.class, "click", RendererClickEvent.class); + + /** + * Called when a rendered button is clicked. + * + * @param event + * the event representing the click + */ + void click(RendererClickEvent event); + } + + /** + * An event fired when a button rendered by a ButtonRenderer is clicked. + */ + public static class RendererClickEvent extends ClickEvent { + + private Object itemId; + + protected RendererClickEvent(Grid source, Object itemId, + MouseEventDetails mouseEventDetails) { + super(source, mouseEventDetails); + this.itemId = itemId; + } + + /** + * Returns the item ID of the row where the click event originated. + * + * @return the item ID of the clicked row + */ + public Object getItemId() { + return itemId; + } + } + + /** + * Creates a new button renderer. + */ + public ButtonRenderer() { + super(String.class); + registerRpc(new RendererClickRpc() { + @Override + public void click(int row, int column, + MouseEventDetails mouseDetails) { + + Grid grid = (Grid) getParent(); + + Object itemId = grid.getContainerDatasource().getIdByIndex(row); + + fireEvent(new RendererClickEvent(grid, itemId, mouseDetails)); + } + }); + } + + /** + * Creates a new button renderer and adds the given click listener to it. + */ + public ButtonRenderer(RendererClickListener listener) { + this(); + addClickListener(listener); + } + + /** + * Adds a click listener to this button renderer. The listener is invoked + * every time one of the buttons rendered by this renderer is clicked. + * + * @param listener + * the click listener to be added + */ + public void addClickListener(RendererClickListener listener) { + addListener(RendererClickEvent.class, listener, + RendererClickListener.CLICK_METHOD); + } + + /** + * Removes the given click listener from this renderer. + * + * @param listener + * the click listener to be removed + */ + public void removeClickListener(RendererClickListener listener) { + removeListener(RendererClickEvent.class, listener); + } +} diff --git a/shared/src/com/vaadin/shared/ui/grid/renderers/RendererClickRpc.java b/shared/src/com/vaadin/shared/ui/grid/renderers/RendererClickRpc.java new file mode 100644 index 0000000000..f83b5aa44f --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/renderers/RendererClickRpc.java @@ -0,0 +1,30 @@ +/* + * 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.shared.ui.grid.renderers; + +import com.vaadin.shared.MouseEventDetails; +import com.vaadin.shared.communication.ServerRpc; + +public interface RendererClickRpc extends ServerRpc { + /** + * Called when a click event has occurred and there are server side + * listeners for the event. + * + * @param mouseDetails + * Details about the mouse when the event took place + */ + public void click(int row, int column, MouseEventDetails mouseDetails); +} diff --git a/uitest/src/com/vaadin/tests/components/grid/WidgetRenderers.java b/uitest/src/com/vaadin/tests/components/grid/WidgetRenderers.java index a0d0179ecc..6fe1e9fcc7 100644 --- a/uitest/src/com/vaadin/tests/components/grid/WidgetRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/WidgetRenderers.java @@ -15,11 +15,15 @@ */ package com.vaadin.tests.components.grid; +import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.ui.components.grid.Grid; import com.vaadin.ui.components.grid.Grid.SelectionMode; +import com.vaadin.ui.components.grid.renderers.ButtonRenderer; +import com.vaadin.ui.components.grid.renderers.ButtonRenderer.RendererClickEvent; +import com.vaadin.ui.components.grid.renderers.ButtonRenderer.RendererClickListener; import com.vaadin.ui.components.grid.renderers.ProgressBarRenderer; public class WidgetRenderers extends AbstractTestUI { @@ -27,11 +31,16 @@ public class WidgetRenderers extends AbstractTestUI { @Override protected void setup(VaadinRequest request) { IndexedContainer container = new IndexedContainer(); + container.addContainerProperty(ProgressBarRenderer.class, Double.class, null); + container + .addContainerProperty(ButtonRenderer.class, String.class, null); + + final Item item = container.getItem(container.addItem()); - container.getItem(container.addItem()) - .getItemProperty(ProgressBarRenderer.class).setValue(0.5); + item.getItemProperty(ProgressBarRenderer.class).setValue(0.3); + item.getItemProperty(ButtonRenderer.class).setValue("Click"); Grid grid = new Grid(container); grid.setId("test-grid"); @@ -40,12 +49,21 @@ public class WidgetRenderers extends AbstractTestUI { grid.getColumn(ProgressBarRenderer.class).setRenderer( new ProgressBarRenderer()); + grid.getColumn(ButtonRenderer.class).setRenderer( + new ButtonRenderer(new RendererClickListener() { + @Override + public void click(RendererClickEvent event) { + item.getItemProperty(ButtonRenderer.class).setValue( + "Clicked!"); + } + })); + addComponent(grid); } @Override protected String getTestDescription() { - return "Tests the working of widget-based renderers"; + return "Tests the functionality of widget-based renderers"; } @Override diff --git a/uitest/src/com/vaadin/tests/components/grid/WidgetRenderersTest.java b/uitest/src/com/vaadin/tests/components/grid/WidgetRenderersTest.java index 183f2cc90a..9ca45a6178 100644 --- a/uitest/src/com/vaadin/tests/components/grid/WidgetRenderersTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/WidgetRenderersTest.java @@ -15,11 +15,14 @@ */ package com.vaadin.tests.components.grid; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Test; +import org.openqa.selenium.WebElement; import com.vaadin.testbench.By; +import com.vaadin.tests.components.grid.GridElement.GridCellElement; import com.vaadin.tests.tb3.MultiBrowserTest; /** @@ -34,7 +37,23 @@ public class WidgetRenderersTest extends MultiBrowserTest { public void testProgressBarRenderer() { openTestURL(); - assertTrue($(GridElement.class).first().getCell(0, 0) - .isElementPresent(By.className("v-progressbar"))); + assertTrue(getGridCell(0, 0).isElementPresent( + By.className("v-progressbar"))); + } + + @Test + public void testButtonRenderer() { + openTestURL(); + + WebElement button = getGridCell(0, 1).findElement( + By.className("gwt-Button")); + + button.click(); + + assertEquals("Clicked!", button.getText()); + } + + GridCellElement getGridCell(int row, int col) { + return $(GridElement.class).first().getCell(row, col); } } -- 2.39.5