]> source.dussan.org Git - vaadin-framework.git/commitdiff
Implemented WidgetRenderer #12993
authorJohn Ahlroos <john@vaadin.com>
Tue, 3 Jun 2014 10:52:33 +0000 (13:52 +0300)
committerJohn Ahlroos <john@vaadin.com>
Tue, 10 Jun 2014 09:08:37 +0000 (12:08 +0300)
Change-Id: I6eb69bd0c18adba057e9785778e0392e1ff25a22

client/src/com/vaadin/client/ui/grid/Escalator.java
client/src/com/vaadin/client/ui/grid/FlyweightCell.java
client/src/com/vaadin/client/ui/grid/Grid.java
client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java [new file with mode: 0644]

index e25e1a2851a4a7fb63bd4d12b906e7b7e0827caf..3af7c76da82dc0f9a69eea21905d8191495cc9df 100644 (file)
@@ -1197,10 +1197,6 @@ public class Escalator extends Widget {
             getEscalatorUpdater().preDetach(flyweightRow,
                     flyweightRow.getCells());
 
-            for (int c = 0; c < tr.getChildCount(); c++) {
-                // TODO this should be WidgetRenderer's responsibility
-                detachPossibleWidgetFromCell((Element) tr.getChild(c).cast());
-            }
             tr.removeFromParent();
 
             getEscalatorUpdater().postDetach(flyweightRow,
@@ -1503,7 +1499,6 @@ public class Escalator extends Widget {
 
                 for (FlyweightCell cell : cells) {
                     Element cellElement = cell.getElement();
-                    detachPossibleWidgetFromCell(cellElement);
                     cellElement.removeFromParent();
                 }
 
@@ -1555,18 +1550,6 @@ public class Escalator extends Widget {
             }
         }
 
-        void detachPossibleWidgetFromCell(Node cellNode) {
-            // Detach possible widget
-            Widget widget = getWidgetFromCell(cellNode);
-            if (widget != null) {
-                // Orphan.
-                setParent(widget, null);
-
-                // Physical detach.
-                cellNode.removeChild(widget.getElement());
-            }
-        }
-
         protected void paintInsertColumns(final int offset,
                 final int numberOfColumns, boolean frozen) {
             final NodeList<Node> childNodes = root.getChildNodes();
@@ -1620,7 +1603,7 @@ public class Escalator extends Widget {
          * Precondition: The row must be already attached to the DOM and the
          * FlyweightCell instances corresponding to the new columns added to
          * {@code flyweightRow}.
-         *
+         * 
          * @param tr
          *            the row in which to insert the cells
          * @param logicalRowIndex
@@ -3340,10 +3323,6 @@ public class Escalator extends Widget {
                         .listIterator(visualRowOrder.size());
                 for (int i = 0; i < -neededEscalatorRowsDiff; i++) {
                     final Element last = iter.previous();
-                    for (int c = 0; c < last.getChildCount(); c++) {
-                        detachPossibleWidgetFromCell((Element) last.getChild(c)
-                                .cast());
-                    }
                     last.removeFromParent();
                     iter.remove();
                 }
@@ -4404,19 +4383,6 @@ public class Escalator extends Widget {
                 body.getLogicalRowIndex(body.visualRowOrder.getLast()) + 1);
     }
 
-    /**
-     * Accesses the package private method Widget#setParent()
-     * 
-     * @param widget
-     *            The widget to access
-     * @param parent
-     *            The parent to set
-     */
-    static native final void setParent(Widget widget, Widget parent)
-    /*-{
-        widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent);
-    }-*/;
-
     /**
      * Returns the widget from a cell node or <code>null</code> if there is no
      * widget in the cell
index 1b956258ffcf694f3b6b1e1a3edd48f2f027e8d4..a7d0ffa989edfe66d7b007297a27137db973f621 100644 (file)
@@ -20,8 +20,6 @@ import java.util.List;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.Style.Display;
 import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.user.client.ui.IsWidget;
-import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.ui.grid.FlyweightRow.CellIterator;
 
 /**
@@ -185,59 +183,4 @@ public class FlyweightCell {
             }
         }
     }
-
-    /**
-     * @deprecated Will be removed in further refactorings
-     */
-    @Deprecated
-    public Widget getWidget() {
-        return Escalator.getWidgetFromCell(getElement());
-    }
-
-    /**
-     * @deprecated Will be removed in further refactorings
-     */
-    @Deprecated
-    public void setWidget(Widget widget) {
-
-        Widget oldWidget = getWidget();
-
-        // Validate
-        if (oldWidget == widget) {
-            return;
-        }
-
-        // Detach old child.
-        if (oldWidget != null) {
-            // Orphan.
-            Escalator.setParent(oldWidget, null);
-
-            // Physical detach.
-            getElement().removeChild(oldWidget.getElement());
-        }
-
-        // Remove any previous text nodes from previous
-        // setInnerText/setInnerHTML
-        getElement().removeAllChildren();
-
-        // Attach new child.
-        if (widget != null) {
-            // Detach new child from old parent.
-            widget.removeFromParent();
-
-            // Physical attach.
-            getElement().appendChild(widget.getElement());
-
-            Escalator.setParent(widget, escalator);
-        }
-    }
-
-    /**
-     * @deprecated Will be removed in further refactorings
-     */
-    @Deprecated
-    public void setWidget(IsWidget w) {
-        setWidget(Widget.asWidgetOrNull(w));
-    }
-
 }
index 0c38e984c1bb6ebfbd9b8c2a78c5a26aad911cad..4bb13990a5ad5da2b136d0fe9497a6a6d3e92a96 100644 (file)
@@ -33,11 +33,14 @@ import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.HasVisibility;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.Util;
 import com.vaadin.client.data.DataChangeHandler;
 import com.vaadin.client.data.DataSource;
 import com.vaadin.client.ui.SubPartAware;
 import com.vaadin.client.ui.grid.renderers.ComplexRenderer;
 import com.vaadin.client.ui.grid.renderers.TextRenderer;
+import com.vaadin.client.ui.grid.renderers.WidgetRenderer;
 import com.vaadin.client.ui.grid.selection.MultiSelectionRenderer;
 import com.vaadin.shared.ui.grid.GridConstants;
 import com.vaadin.shared.ui.grid.HeightMode;
@@ -774,49 +777,68 @@ public class Grid<T> extends Composite implements SubPartAware {
         return new EscalatorUpdater() {
 
             @Override
-            public void update(Row row, Iterable<FlyweightCell> cellsToUpdate) {
-                int rowIndex = row.getRow();
-                if (dataSource == null) {
-                    setCellsLoading(cellsToUpdate);
-                    return;
+            public void preAttach(Row row, Iterable<FlyweightCell> cellsToAttach) {
+                // NOP
+            }
+
+            @Override
+            public void postAttach(Row row,
+                    Iterable<FlyweightCell> attachedCells) {
+                for (FlyweightCell cell : attachedCells) {
+                    Renderer renderer = findRenderer(cell);
+                    if (renderer instanceof WidgetRenderer) {
+                        WidgetRenderer widgetRenderer = (WidgetRenderer) renderer;
+
+                        Widget widget = widgetRenderer.createWidget();
+                        assert widget != null : "WidgetRenderer.createWidget() returned null. It should return a widget.";
+                        assert widget.getParent() == null : "WidgetRenderer.createWidget() returned a widget which already is attached.";
+                        assert cell.getElement().getChildCount() == 0 : "Cell content should be empty when adding Widget";
+
+                        // Physical attach
+                        cell.getElement().appendChild(widget.getElement());
+
+                        // Logical attach
+                        setParent(widget, Grid.this);
+                    }
                 }
+            }
 
+            @Override
+            public void update(Row row, Iterable<FlyweightCell> cellsToUpdate) {
+                int rowIndex = row.getRow();
                 T rowData = dataSource.getRow(rowIndex);
                 if (rowData == null) {
-                    setCellsLoading(cellsToUpdate);
                     return;
                 }
 
                 for (FlyweightCell cell : cellsToUpdate) {
                     GridColumn column = getColumnFromVisibleIndex(cell
                             .getColumn());
-                    if (column != null) {
-                        Object value = column.getValue(rowData);
-                        column.getRenderer().render(cell, value);
-                    }
-                }
-            }
-
-            private void setCellsLoading(Iterable<FlyweightCell> cellsToUpdate) {
-                for (FlyweightCell cell : cellsToUpdate) {
-                    cell.getElement().setInnerText("...");
+                    assert column != null : "Column was not found from cell ("
+                            + cell.getColumn() + "," + cell.getRow() + ")";
+                    Object value = column.getValue(rowData);
+                    Renderer renderer = findRenderer(cell);
+                    renderer.render(cell, value);
                 }
             }
 
-            @Override
-            public void preAttach(Row row, Iterable<FlyweightCell> cellsToAttach) {
-                // NOOP for now
-            }
-
-            @Override
-            public void postAttach(Row row,
-                    Iterable<FlyweightCell> attachedCells) {
-                // NOOP for now
-            }
-
             @Override
             public void preDetach(Row row, Iterable<FlyweightCell> cellsToDetach) {
-                // NOOP for now
+                for (FlyweightCell cell : cellsToDetach) {
+                    Renderer renderer = findRenderer(cell);
+                    if (renderer instanceof WidgetRenderer) {
+                        Widget w = Util.findWidget(cell.getElement()
+                                .getFirstChildElement(), Widget.class);
+                        if (w != null) {
+
+                            // Logical detach
+                            setParent(w, null);
+
+                            // Physical detach
+                            cell.getElement().removeChild(w.getElement());
+                        }
+                    }
+                }
             }
 
             @Override
@@ -1027,6 +1049,13 @@ public class Grid<T> extends Composite implements SubPartAware {
         return null;
     }
 
+    private Renderer findRenderer(FlyweightCell cell) {
+        GridColumn column = getColumnFromVisibleIndex(cell.getColumn());
+        assert column != null : "Could not find column at index:"
+                + cell.getColumn();
+        return column.getRenderer();
+    }
+
     /**
      * Removes a column from the grid.
      * 
@@ -1735,4 +1764,17 @@ public class Grid<T> extends Composite implements SubPartAware {
     private boolean isSelected(T row) {
         return false;
     }
+
+    /**
+     * Accesses the package private method Widget#setParent()
+     * 
+     * @param widget
+     *            The widget to access
+     * @param parent
+     *            The parent to set
+     */
+    private static native final void setParent(Widget widget, Widget parent)
+    /*-{
+        widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent);
+    }-*/;
 }
diff --git a/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java
new file mode 100644 (file)
index 0000000..0937e8c
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.user.client.ui.Widget;
+import com.vaadin.client.Util;
+import com.vaadin.client.ui.grid.FlyweightCell;
+
+/**
+ * A renderer for rendering widgets into cells.
+ * 
+ * @since 7.4
+ * @author Vaadin Ltd
+ * @param <T>
+ *            the row data type
+ * @param <W>
+ *            the Widget type
+ */
+public abstract class WidgetRenderer<T, W extends Widget> extends
+        ComplexRenderer<T> {
+
+    /**
+     * Creates a widget to attach to a cell. The widgets will be attached to the
+     * cell after the cell element has been attached to DOM.
+     * 
+     * @return widget to attach to a cell. All returned instances should be new
+     *         widget instances without a parent.
+     */
+    public abstract W createWidget();
+
+    @Override
+    public void render(FlyweightCell cell, T data) {
+        W w = Util.findWidget(cell.getElement().getFirstChildElement(), null);
+        assert w != null : "Widget not found in cell (" + cell.getColumn()
+                + "," + cell.getRow() + ")";
+        render(cell, data, w);
+    }
+
+    /**
+     * Renders a cell with a widget. This provides a way to update any
+     * information in the widget that is cell specific. Do not detach the Widget
+     * here, it will be done automatically by the Grid when the widget is no
+     * longer needed.
+     * 
+     * @param cell
+     *            the cell to render
+     * @param data
+     *            the data of the cell
+     * @param widget
+     *            the widget embedded in the cell
+     */
+    public abstract void render(FlyweightCell cell, T data, W widget);
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java
new file mode 100644 (file)
index 0000000..2e1a9ab
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.openqa.selenium.Alert;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.testbench.elements.NativeButtonElement;
+import com.vaadin.testbench.elements.NativeSelectElement;
+import com.vaadin.testbench.elements.ServerClass;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+import com.vaadin.tests.widgetset.client.grid.GridClientColumnRendererConnector.Renderers;
+import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers;
+
+/**
+ * Tests Grid client side renderers
+ * 
+ * @since 7.4
+ * @author Vaadin Ltd
+ */
+public class GridClientRenderers extends MultiBrowserTest {
+
+    @Override
+    protected Class<?> getUIClass() {
+        return GridClientColumnRenderers.class;
+    }
+
+    @ServerClass("com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers.GridController")
+    public static class MyClientGridElement extends GridElement {
+    }
+
+    @Test
+    public void addWidgetRenderer() throws Exception {
+        openTestURL();
+
+        // Add widget renderer column
+        $(NativeSelectElement.class).first().selectByText(
+                Renderers.WIDGET_RENDERER.toString());
+        $(NativeButtonElement.class).caption("Add").first().click();
+
+        // Click the button in cell 1,1
+        TestBenchElement cell = getGrid().getCell(1, 1);
+        WebElement gwtButton = cell.findElement(By.tagName("button"));
+        gwtButton.click();
+
+        // Should be an alert visible
+        Alert alert = driver.switchTo().alert();
+        assertEquals(alert.getText(), "Click");
+    }
+
+    @Test
+    public void detachAndAttachGrid() {
+        openTestURL();
+
+        // Add widget renderer column
+        $(NativeSelectElement.class).first().selectByText(
+                Renderers.WIDGET_RENDERER.toString());
+        $(NativeButtonElement.class).caption("Add").first().click();
+
+        // Detach and re-attach the Grid
+        $(NativeButtonElement.class).caption("DetachAttach").first().click();
+
+        // Click the button in cell 1,1
+        TestBenchElement cell = getGrid().getCell(1, 1);
+        WebElement gwtButton = cell.findElement(By.tagName("button"));
+        gwtButton.click();
+
+        // Should be an alert visible
+        Alert alert = driver.switchTo().alert();
+        assertEquals(alert.getText(), "Click");
+    }
+
+    private GridElement getGrid() {
+        return $(MyClientGridElement.class).first();
+    }
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java
new file mode 100644 (file)
index 0000000..a4403f5
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.client.ui.grid.FlyweightCell;
+import com.vaadin.client.ui.grid.Grid;
+import com.vaadin.client.ui.grid.GridColumn;
+import com.vaadin.client.ui.grid.Renderer;
+import com.vaadin.client.ui.grid.datasources.ListDataSource;
+import com.vaadin.client.ui.grid.renderers.DateRenderer;
+import com.vaadin.client.ui.grid.renderers.HtmlRenderer;
+import com.vaadin.client.ui.grid.renderers.NumberRenderer;
+import com.vaadin.client.ui.grid.renderers.TextRenderer;
+import com.vaadin.client.ui.grid.renderers.WidgetRenderer;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers;
+
+@Connect(GridClientColumnRenderers.GridController.class)
+public class GridClientColumnRendererConnector extends
+        AbstractComponentConnector {
+
+    public static enum Renderers {
+        TEXT_RENDERER, WIDGET_RENDERER, HTML_RENDERER, NUMBER_RENDERER, DATE_RENDERER;
+    }
+
+    @Override
+    protected void init() {
+        Grid<String> grid = getWidget();
+        grid.setColumnHeadersVisible(false);
+
+        // Generated some column data
+        List<String> columnData = new ArrayList<String>();
+        for (int i = 0; i < 100; i++) {
+            columnData.add(String.valueOf(i));
+        }
+
+        // Provide data as data source
+        grid.setDataSource(new ListDataSource<String>(columnData));
+
+        // Add a column to display the data in
+        grid.addColumn(createColumnWithRenderer(Renderers.TEXT_RENDERER));
+
+        // Handle RPC calls
+        registerRpc(GridClientColumnRendererRpc.class,
+                new GridClientColumnRendererRpc() {
+
+                    @Override
+                    public void addColumn(Renderers renderer) {
+
+                        if (renderer == Renderers.NUMBER_RENDERER) {
+                            getWidget().addColumn(
+                                    createNumberColumnWithRenderer(renderer));
+                        } else if (renderer == Renderers.DATE_RENDERER) {
+                            getWidget().addColumn(
+                                    createDateColumnWithRenderer(renderer));
+
+                        } else {
+                            getWidget().addColumn(
+                                    createColumnWithRenderer(renderer));
+                        }
+                    }
+
+                    @Override
+                    public void detachAttach() {
+
+                        // Detach
+                        HasWidgets parent = (HasWidgets) getWidget()
+                                .getParent();
+                        parent.remove(getWidget());
+
+                        // Re-attach
+                        parent.add(getWidget());
+                    }
+                });
+    }
+
+    /**
+     * Creates a a renderer for a {@link Renderers}
+     */
+    private Renderer createRenderer(Renderers renderer) {
+        switch (renderer) {
+        case TEXT_RENDERER:
+            return new TextRenderer();
+
+        case WIDGET_RENDERER:
+            return new WidgetRenderer<String, Button>() {
+
+                @Override
+                public Button createWidget() {
+                    return new Button("", new ClickHandler() {
+
+                        @Override
+                        public void onClick(ClickEvent event) {
+                            Window.alert("Click");
+                        }
+                    });
+                }
+
+                @Override
+                public void render(FlyweightCell cell, String data,
+                        Button button) {
+                    button.setHTML(data);
+                }
+            };
+
+        case HTML_RENDERER:
+            return new HtmlRenderer() {
+
+                @Override
+                public void render(FlyweightCell cell, String htmlString) {
+                    super.render(cell, "<b>" + htmlString + "</b>");
+                }
+            };
+
+        case NUMBER_RENDERER:
+            return new NumberRenderer<Long>();
+
+        case DATE_RENDERER:
+            return new DateRenderer();
+
+        default:
+            return new TextRenderer();
+        }
+    }
+
+    private GridColumn<String, String> createColumnWithRenderer(
+            Renderers renderer) {
+        return new GridColumn<String, String>(createRenderer(renderer)) {
+
+            @Override
+            public String getValue(String row) {
+                return row;
+            }
+        };
+    }
+
+    private GridColumn<Number, String> createNumberColumnWithRenderer(
+            Renderers renderer) {
+        return new GridColumn<Number, String>(createRenderer(renderer)) {
+
+            @Override
+            public Number getValue(String row) {
+                return Long.parseLong(row);
+            }
+        };
+    }
+
+    private GridColumn<Date, String> createDateColumnWithRenderer(
+            Renderers renderer) {
+        return new GridColumn<Date, String>(createRenderer(renderer)) {
+
+            @Override
+            public Date getValue(String row) {
+                return new Date();
+            }
+        };
+    }
+
+    @Override
+    public Grid<String> getWidget() {
+        return (Grid<String>) super.getWidget();
+    }
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java
new file mode 100644 (file)
index 0000000..d156bf9
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 com.vaadin.shared.communication.ClientRpc;
+import com.vaadin.tests.widgetset.client.grid.GridClientColumnRendererConnector.Renderers;
+
+public interface GridClientColumnRendererRpc extends ClientRpc {
+
+    /**
+     * Adds a new column with a specific renderer to the grid
+     * 
+     */
+    void addColumn(Renderers renderer);
+
+    /**
+     * Detaches and attaches the client side Grid
+     */
+    void detachAttach();
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java b/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java
new file mode 100644 (file)
index 0000000..e968f13
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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.server.grid;
+
+import java.util.Arrays;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.tests.widgetset.client.grid.GridClientColumnRendererConnector.Renderers;
+import com.vaadin.tests.widgetset.client.grid.GridClientColumnRendererRpc;
+import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.NativeButton;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalLayout;
+
+@Widgetset(TestingWidgetSet.NAME)
+public class GridClientColumnRenderers extends UI {
+
+    /**
+     * Controls the grid on the client side
+     */
+    public static class GridController extends AbstractComponent {
+
+        private GridClientColumnRendererRpc rpc() {
+            return getRpcProxy(GridClientColumnRendererRpc.class);
+        }
+
+        /**
+         * Adds a new column with a renderer to the grid.
+         */
+        public void addColumn(Renderers renderer) {
+            rpc().addColumn(renderer);
+        }
+
+        /**
+         * Tests detaching and attaching grid
+         */
+        public void detachAttach() {
+            rpc().detachAttach();
+        }
+    }
+
+    @Override
+    protected void init(VaadinRequest request) {
+        final GridController controller = new GridController();
+        final CssLayout controls = new CssLayout();
+        final VerticalLayout content = new VerticalLayout();
+
+        content.addComponent(controller);
+        content.addComponent(controls);
+        setContent(content);
+
+        final NativeSelect select = new NativeSelect(
+                "Add Column with Renderer", Arrays.asList(Renderers.values()));
+        select.setValue(Renderers.TEXT_RENDERER);
+        select.setNullSelectionAllowed(false);
+        controls.addComponent(select);
+
+        NativeButton addColumnBtn = new NativeButton("Add");
+        addColumnBtn.addClickListener(new ClickListener() {
+
+            @Override
+            public void buttonClick(ClickEvent event) {
+                Renderers renderer = (Renderers) select.getValue();
+                controller.addColumn(renderer);
+            }
+        });
+        controls.addComponent(addColumnBtn);
+
+        NativeButton detachAttachBtn = new NativeButton("DetachAttach");
+        detachAttachBtn.addClickListener(new ClickListener() {
+
+            @Override
+            public void buttonClick(ClickEvent event) {
+                controller.detachAttach();
+            }
+        });
+        controls.addComponent(detachAttachBtn);
+    }
+}