aboutsummaryrefslogtreecommitdiffstats
path: root/uitest/src
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2014-09-20 10:01:44 +0300
committerLeif Åstrand <leif@vaadin.com>2014-09-20 10:15:37 +0300
commit9542a79187efc287e0ac5d1c7ca3911587e6f059 (patch)
tree175e18bd43f3d4c73d7d2eb6a277f81be8dd8488 /uitest/src
parent526b23cd86ccc7603e280da45d48f3f4bfcc4ecd (diff)
parent48e208c78e1ca2227d422985e4084a8b1ed7304f (diff)
downloadvaadin-framework-9542a79187efc287e0ac5d1c7ca3911587e6f059.tar.gz
vaadin-framework-9542a79187efc287e0ac5d1c7ca3911587e6f059.zip
Merge remote-tracking branch 'origin/master' into grid
Change-Id: I8a35a090619778b1cfbff55e112ab2f30e6881a2
Diffstat (limited to 'uitest/src')
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java76
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java62
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java281
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridColspans.java79
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridColspansTest.java73
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridElement.java284
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridScrolling.java112
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java59
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java45
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java37
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java42
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeatures.java36
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java194
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorColspanTest.java91
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorColumnFreezingTest.java112
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorRowColumnTest.java203
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorUpdaterUi.java35
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorUpdaterUiTest.java148
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeatures.java41
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java63
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java750
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java119
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientColumnPropertiesTest.java77
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientKeyEventsTest.java127
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java37
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java154
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java119
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridFooterTest.java207
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridHeaderTest.java359
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridStaticSectionTest.java90
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridStylingTest.java119
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridActiveCellAdjustmentTest.java49
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridKeyboardNavigationTest.java225
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java179
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java273
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java54
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java252
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml2
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesConnector.java37
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java608
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java206
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorUpdaterTestConnector.java30
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesConnector.java37
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java931
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java380
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java48
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java46
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/PureGWTTestApplication.java308
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java76
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java153
50 files changed, 8125 insertions, 0 deletions
diff --git a/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java b/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java
new file mode 100644
index 0000000000..d217829bcb
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java
@@ -0,0 +1,76 @@
+/*
+ * 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 com.vaadin.annotations.Widgetset;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+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;
+import com.vaadin.ui.components.grid.Grid.SelectionMode;
+
+@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);
+
+ @SuppressWarnings("unchecked")
+ 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));
+ grid.setSelectionMode(SelectionMode.NONE);
+ addComponent(grid);
+ addComponent(debugLabel);
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Verifies that renderers operating on other data than "
+ + "just Strings also work ";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(13334);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java b/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java
new file mode 100644
index 0000000000..571a929c7e
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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 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;
+
+@TestCategory("grid")
+public class CustomRendererTest extends MultiBrowserTest {
+ @Test
+ public void testIntArrayIsRendered() throws Exception {
+ openTestURL();
+
+ GridElement grid = findGrid();
+ assertEquals("1 :: 1 :: 2 :: 3 :: 5 :: 8 :: 13", grid.getCell(0, 0)
+ .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);
+ }
+}
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
index 0000000000..2656407023
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java
@@ -0,0 +1,281 @@
+/*
+ * 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.remote.DesiredCapabilities;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.testbench.elements.NativeButtonElement;
+import com.vaadin.testbench.elements.NativeSelectElement;
+import com.vaadin.testbench.elements.ServerClass;
+import com.vaadin.tests.annotations.TestCategory;
+import com.vaadin.tests.components.grid.GridElement.GridCellElement;
+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
+ * @author Vaadin Ltd
+ */
+@TestCategory("grid")
+public class GridClientRenderers extends MultiBrowserTest {
+
+ private static final double SLEEP_MULTIPLIER = 1.2;
+ private int latency = 0;
+
+ @Override
+ protected Class<?> getUIClass() {
+ return GridClientColumnRenderers.class;
+ }
+
+ @Override
+ protected String getDeploymentPath() {
+ String path = super.getDeploymentPath();
+ if (latency > 0) {
+ path += (path.contains("?") ? "&" : "?") + "latency=" + latency;
+ }
+ return path;
+ }
+
+ @ServerClass("com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers.GridController")
+ public static class MyClientGridElement extends GridElement {
+ }
+
+ @Override
+ public void setup() throws Exception {
+ latency = 0; // reset
+ super.setup();
+ }
+
+ @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, 2);
+ WebElement gwtButton = cell.findElement(By.tagName("button"));
+ gwtButton.click();
+
+ // Should be an alert visible
+ assertEquals("Button did not contain text \"Clicked\"", "Clicked",
+ gwtButton.getText());
+ }
+
+ @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, 2);
+ WebElement gwtButton = cell.findElement(By.tagName("button"));
+ gwtButton.click();
+
+ // Should be an alert visible
+ assertEquals("Button did not contain text \"Clicked\"",
+ gwtButton.getText(), "Clicked");
+ }
+
+ @Test
+ public void rowsWithDataHasStyleName() throws Exception {
+
+ // Simulate network latency with 2000ms
+ latency = 2000;
+
+ openTestURL();
+
+ sleep((int) (latency * SLEEP_MULTIPLIER));
+
+ TestBenchElement row = getGrid().getRow(51);
+ String className = row.getAttribute("class");
+ assertFalse(
+ "Row should not yet contain style name v-grid-row-has-data",
+ className.contains("v-grid-row-has-data"));
+
+ // Wait for data to arrive
+ sleep((int) (latency * SLEEP_MULTIPLIER));
+
+ row = getGrid().getRow(51);
+ className = row.getAttribute("class");
+ assertTrue("Row should now contain style name v-grid-row-has-data",
+ className.contains("v-grid-row-has-data"));
+ }
+
+ @Test
+ public void complexRendererSetVisibleContent() throws Exception {
+
+ DesiredCapabilities desiredCapabilities = getDesiredCapabilities();
+
+ // Simulate network latency with 2000ms
+ latency = 2000;
+ if (BrowserUtil.isIE8(desiredCapabilities)) {
+ // IE8 is slower than other browsers. Bigger latency is needed for
+ // stability in this test.
+ latency = 3000;
+ }
+
+ // Chrome uses RGB instead of RGBA
+ String colorRed = "rgba(255, 0, 0, 1)";
+ String colorWhite = "rgba(255, 255, 255, 1)";
+ if (BrowserUtil.isChrome(desiredCapabilities)) {
+ colorRed = "rgb(255, 0, 0)";
+ colorWhite = "rgb(255, 255, 255)";
+ }
+
+ openTestURL();
+
+ // Test initial renderering with contentVisible = False
+ TestBenchElement cell = getGrid().getCell(51, 1);
+ String backgroundColor = cell.getCssValue("backgroundColor");
+ assertEquals("Background color was not red.", colorRed, backgroundColor);
+
+ // data arrives...
+ sleep((int) (latency * SLEEP_MULTIPLIER));
+
+ // Content becomes visible
+ cell = getGrid().getCell(51, 1);
+ backgroundColor = cell.getCssValue("backgroundColor");
+ assertNotEquals("Background color was red.", colorRed, backgroundColor);
+
+ // scroll down, new cells becomes contentVisible = False
+ getGrid().scrollToRow(60);
+
+ // Cell should be red (setContentVisible set cell red)
+ cell = getGrid().getCell(55, 1);
+ backgroundColor = cell.getCssValue("backgroundColor");
+ assertEquals("Background color was not red.", colorRed, backgroundColor);
+
+ // data arrives...
+ sleep((int) (latency * SLEEP_MULTIPLIER));
+
+ // Cell should no longer be red
+ backgroundColor = cell.getCssValue("backgroundColor");
+ assertEquals("Background color was not white", colorWhite,
+ backgroundColor);
+ }
+
+ @Test
+ public void testSortingEvent() throws Exception {
+ openTestURL();
+
+ $(NativeButtonElement.class).caption("Trigger sorting event").first()
+ .click();
+
+ String consoleText = $(LabelElement.class).id("testDebugConsole")
+ .getText();
+
+ assertTrue("Console text as expected",
+ consoleText.contains("Columns: 1, order: Column 1: ASCENDING"));
+
+ }
+
+ @Test
+ public void testListSorter() throws Exception {
+ openTestURL();
+
+ $(NativeButtonElement.class).caption("Shuffle").first().click();
+
+ GridElement gridElem = $(MyClientGridElement.class).first();
+
+ // XXX: DANGER! We'll need to know how many rows the Grid has!
+ // XXX: Currently, this is impossible; hence the hardcoded value of 70.
+
+ boolean shuffled = false;
+ for (int i = 1, l = 70; i < l; ++i) {
+
+ String str_a = gridElem.getCell(i - 1, 0).getAttribute("innerHTML");
+ String str_b = gridElem.getCell(i, 0).getAttribute("innerHTML");
+
+ int value_a = Integer.parseInt(str_a);
+ int value_b = Integer.parseInt(str_b);
+
+ if (value_a > value_b) {
+ shuffled = true;
+ break;
+ }
+ }
+ assertTrue("Grid shuffled", shuffled);
+
+ $(NativeButtonElement.class).caption("Test sorting").first().click();
+
+ for (int i = 1, l = 70; i < l; ++i) {
+
+ String str_a = gridElem.getCell(i - 1, 0).getAttribute("innerHTML");
+ String str_b = gridElem.getCell(i, 0).getAttribute("innerHTML");
+
+ int value_a = Integer.parseInt(str_a);
+ int value_b = Integer.parseInt(str_b);
+
+ if (value_a > value_b) {
+ assertTrue("Grid sorted", false);
+ }
+ }
+ }
+
+ @Test
+ public void testComplexRendererOnActivate() {
+ openTestURL();
+
+ GridCellElement cell = getGrid().getCell(3, 1);
+ cell.click();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ assertEquals("onActivate was not called on KeyDown Enter.",
+ "Activated!", cell.getText());
+
+ cell = getGrid().getCell(4, 1);
+ cell.click();
+ new Actions(getDriver()).moveToElement(cell).doubleClick().perform();
+ assertEquals("onActivate was not called on double click.",
+ "Activated!", cell.getText());
+ }
+
+ private GridElement getGrid() {
+ return $(MyClientGridElement.class).first();
+ }
+
+ private void addColumn(Renderers renderer) {
+ // Add widget renderer column
+ $(NativeSelectElement.class).first().selectByText(renderer.toString());
+ $(NativeButtonElement.class).caption("Add").first().click();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridColspans.java b/uitest/src/com/vaadin/tests/components/grid/GridColspans.java
new file mode 100644
index 0000000000..7b905d5404
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridColspans.java
@@ -0,0 +1,79 @@
+/*
+ * 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 com.vaadin.data.Container.Indexed;
+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.GridFooter;
+import com.vaadin.ui.components.grid.GridFooter.FooterRow;
+import com.vaadin.ui.components.grid.GridHeader;
+import com.vaadin.ui.components.grid.GridHeader.HeaderRow;
+import com.vaadin.ui.components.grid.renderers.NumberRenderer;
+
+public class GridColspans extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ Indexed dataSource = new IndexedContainer();
+ Grid grid;
+
+ dataSource.addContainerProperty("firstName", String.class, "");
+ dataSource.addContainerProperty("lastName", String.class, "");
+ dataSource.addContainerProperty("streetAddress", String.class, "");
+ dataSource.addContainerProperty("zipCode", Integer.class, null);
+ dataSource.addContainerProperty("city", String.class, "");
+ Item i = dataSource.addItem(0);
+ i.getItemProperty("firstName").setValue("Rudolph");
+ i.getItemProperty("lastName").setValue("Reindeer");
+ i.getItemProperty("streetAddress").setValue("Ruukinkatu 2-4");
+ i.getItemProperty("zipCode").setValue(20540);
+ i.getItemProperty("city").setValue("Turku");
+ grid = new Grid(dataSource);
+ grid.setWidth("600px");
+ grid.getColumn("zipCode").setRenderer(new NumberRenderer());
+ addComponent(grid);
+
+ GridHeader header = grid.getHeader();
+ HeaderRow row = header.prependRow();
+ row.join("firstName", "lastName").setText("Full Name");
+ row.join("streetAddress", "zipCode", "city").setText("Address");
+ header.prependRow()
+ .join(dataSource.getContainerPropertyIds().toArray())
+ .setText("All the stuff");
+
+ GridFooter footer = grid.getFooter();
+ FooterRow footerRow = footer.appendRow();
+ footerRow.join("firstName", "lastName").setText("Full Name");
+ footerRow.join("streetAddress", "zipCode", "city").setText("Address");
+ footer.appendRow().join(dataSource.getContainerPropertyIds().toArray())
+ .setText("All the stuff");
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Grid header and footer colspans";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 13334;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridColspansTest.java b/uitest/src/com/vaadin/tests/components/grid/GridColspansTest.java
new file mode 100644
index 0000000000..dad9399466
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridColspansTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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 java.io.IOException;
+
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.tests.annotations.TestCategory;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+@TestCategory("grid")
+public class GridColspansTest extends MultiBrowserTest {
+
+ @Test
+ public void testHeaderColSpans() {
+ openTestURL();
+
+ GridElement grid = $(GridElement.class).first();
+ assertEquals("5", grid.getHeaderCell(0, 1).getAttribute("colspan"));
+ assertEquals("2", grid.getHeaderCell(1, 1).getAttribute("colspan"));
+ assertEquals("3", grid.getHeaderCell(1, 3).getAttribute("colspan"));
+ }
+
+ @Test
+ public void testFooterColSpans() {
+ openTestURL();
+
+ GridElement grid = $(GridElement.class).first();
+ assertEquals("5", grid.getFooterCell(1, 1).getAttribute("colspan"));
+ assertEquals("2", grid.getFooterCell(0, 1).getAttribute("colspan"));
+ assertEquals("3", grid.getFooterCell(0, 3).getAttribute("colspan"));
+ }
+
+ @Test
+ public void testActiveHeaderColumnsWithNavigation() throws IOException {
+ openTestURL();
+
+ GridElement grid = $(GridElement.class).first();
+ grid.getCell(0, 1).click();
+
+ compareScreen("beforeNavigation");
+
+ for (int i = 1; i <= 6; ++i) {
+ assertEquals(true, grid.getFooterCell(1, 1).isActiveHeader());
+ assertEquals(i < 3, grid.getFooterCell(0, 1).isActiveHeader());
+ assertEquals(i >= 3, grid.getFooterCell(0, 3).isActiveHeader());
+ assertEquals(true, grid.getHeaderCell(0, 1).isActiveHeader());
+ assertEquals(i < 3, grid.getHeaderCell(1, 1).isActiveHeader());
+ assertEquals(i >= 3, grid.getHeaderCell(1, 3).isActiveHeader());
+ new Actions(getDriver()).sendKeys(Keys.ARROW_RIGHT).perform();
+ }
+
+ compareScreen("afterNavigation");
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridElement.java b/uitest/src/com/vaadin/tests/components/grid/GridElement.java
new file mode 100644
index 0000000000..27c552340a
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridElement.java
@@ -0,0 +1,284 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.testbench.elements.AbstractComponentElement;
+import com.vaadin.testbench.elements.AbstractElement;
+import com.vaadin.testbench.elements.ServerClass;
+
+/**
+ * TestBench Element API for Grid
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+@ServerClass("com.vaadin.ui.components.grid.Grid")
+public class GridElement extends AbstractComponentElement {
+
+ public static class GridCellElement extends AbstractElement {
+
+ private String ACTIVE_CLASS_NAME = "-cell-active";
+ private String ACTIVE_HEADER_CLASS_NAME = "-header-active";
+ private String FROZEN_CLASS_NAME = "frozen";
+
+ public boolean isActive() {
+ return getAttribute("class").contains(ACTIVE_CLASS_NAME);
+ }
+
+ public boolean isActiveHeader() {
+ return getAttribute("class").contains(ACTIVE_HEADER_CLASS_NAME);
+ }
+
+ public boolean isFrozen() {
+ return getAttribute("class").contains(FROZEN_CLASS_NAME);
+ }
+ }
+
+ public static class GridRowElement extends AbstractElement {
+
+ private String ACTIVE_CLASS_NAME = "-row-active";
+ private String SELECTED_CLASS_NAME = "-row-selected";
+
+ public boolean isActive() {
+ return getAttribute("class").contains(ACTIVE_CLASS_NAME);
+ }
+
+ @Override
+ public boolean isSelected() {
+ return getAttribute("class").contains(SELECTED_CLASS_NAME);
+ }
+ }
+
+ /**
+ * Scrolls Grid element so that wanted row is displayed
+ *
+ * @param index
+ * Target row
+ */
+ public void scrollToRow(int index) {
+ try {
+ getSubPart("#cell[" + index + "]");
+ } catch (NoSuchElementException e) {
+ // Expected, ignore it.
+ }
+ }
+
+ /**
+ * Gets cell element with given row and column index.
+ *
+ * @param rowIndex
+ * Row index
+ * @param colIndex
+ * Column index
+ * @return Cell element with given indices.
+ */
+ public GridCellElement getCell(int rowIndex, int colIndex) {
+ scrollToRow(rowIndex);
+ return getSubPart("#cell[" + rowIndex + "][" + colIndex + "]").wrap(
+ GridCellElement.class);
+ }
+
+ /**
+ * Gets row element with given row index.
+ *
+ * @param index
+ * Row index
+ * @return Row element with given index.
+ */
+ public GridRowElement getRow(int index) {
+ scrollToRow(index);
+ return getSubPart("#cell[" + index + "]").wrap(GridRowElement.class);
+ }
+
+ /**
+ * Gets header cell element with given row and column index.
+ *
+ * @param rowIndex
+ * Row index
+ * @param colIndex
+ * Column index
+ * @return Header cell element with given indices.
+ */
+ public GridCellElement getHeaderCell(int rowIndex, int colIndex) {
+ return getSubPart("#header[" + rowIndex + "][" + colIndex + "]").wrap(
+ GridCellElement.class);
+ }
+
+ /**
+ * Gets footer cell element with given row and column index.
+ *
+ * @param rowIndex
+ * Row index
+ * @param colIndex
+ * Column index
+ * @return Footer cell element with given indices.
+ */
+ public GridCellElement getFooterCell(int rowIndex, int colIndex) {
+ return getSubPart("#footer[" + rowIndex + "][" + colIndex + "]").wrap(
+ GridCellElement.class);
+ }
+
+ /**
+ * Gets list of header cell elements on given row.
+ *
+ * @param rowIndex
+ * Row index
+ * @return Header cell elements on given row.
+ */
+ public List<GridCellElement> getHeaderCells(int rowIndex) {
+ List<GridCellElement> headers = new ArrayList<GridCellElement>();
+ for (TestBenchElement e : TestBenchElement.wrapElements(
+ getSubPart("#header[" + rowIndex + "]").findElements(
+ By.xpath("./th")), getCommandExecutor())) {
+ headers.add(e.wrap(GridCellElement.class));
+ }
+ return headers;
+ }
+
+ /**
+ * Gets list of header cell elements on given row.
+ *
+ * @param rowIndex
+ * Row index
+ * @return Header cell elements on given row.
+ */
+ public List<GridCellElement> getFooterCells(int rowIndex) {
+ List<GridCellElement> footers = new ArrayList<GridCellElement>();
+ for (TestBenchElement e : TestBenchElement.wrapElements(
+ getSubPart("#footer[" + rowIndex + "]").findElements(
+ By.xpath("./td")), getCommandExecutor())) {
+ footers.add(e.wrap(GridCellElement.class));
+ }
+ return footers;
+ }
+
+ /**
+ * Get header row count
+ *
+ * @return Header row count
+ */
+ public int getHeaderCount() {
+ return getSubPart("#header").findElements(By.xpath("./tr")).size();
+ }
+
+ /**
+ * Get footer row count
+ *
+ * @return Footer row count
+ */
+ public int getFooterCount() {
+ return getSubPart("#footer").findElements(By.xpath("./tr")).size();
+ }
+
+ /**
+ * Get a header row by index
+ *
+ * @param rowIndex
+ * Row index
+ * @return The th element of the row
+ */
+ public WebElement getHeaderRow(int rowIndex) {
+ return getSubPart("#header[" + rowIndex + "]");
+ }
+
+ /**
+ * Get a footer row by index
+ *
+ * @param rowIndex
+ * Row index
+ * @return The tr element of the row
+ */
+ public WebElement getFooterRow(int rowIndex) {
+ return getSubPart("#footer[" + rowIndex + "]");
+ }
+
+ /**
+ * Get the vertical scroll element
+ *
+ * @return The element representing the vertical scrollbar
+ */
+ public WebElement getVerticalScroller() {
+ List<WebElement> rootElements = findElements(By.xpath("./div"));
+ return rootElements.get(0);
+ }
+
+ /**
+ * Get the horizontal scroll element
+ *
+ * @return The element representing the horizontal scrollbar
+ */
+ public WebElement getHorizontalScroller() {
+ List<WebElement> rootElements = findElements(By.xpath("./div"));
+ return rootElements.get(1);
+ }
+
+ /**
+ * Get the header element
+ *
+ * @return The thead element
+ */
+ public WebElement getHeader() {
+ return getSubPart("#header");
+ }
+
+ /**
+ * Get the body element
+ *
+ * @return the tbody element
+ */
+ public WebElement getBody() {
+ return getSubPart("#cell");
+ }
+
+ /**
+ * Get the footer element
+ *
+ * @return the tfoot element
+ */
+ public WebElement getFooter() {
+ return getSubPart("#footer");
+ }
+
+ /**
+ * Get the element wrapping the table element
+ *
+ * @return The element that wraps the table element
+ */
+ public WebElement getTableWrapper() {
+ List<WebElement> rootElements = findElements(By.xpath("./div"));
+ return rootElements.get(2);
+ }
+
+ /**
+ * Helper function to get Grid subparts wrapped correctly
+ *
+ * @param subPartSelector
+ * SubPart to be used in ComponentLocator
+ * @return SubPart element wrapped in TestBenchElement class
+ */
+ private TestBenchElement getSubPart(String subPartSelector) {
+ return (TestBenchElement) findElement(By.vaadin(subPartSelector));
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java b/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java
new file mode 100644
index 0000000000..dd86d616b9
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java
@@ -0,0 +1,112 @@
+/*
+ * 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 com.vaadin.data.Item;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.grid.ScrollDestination;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.components.grid.Grid;
+
+@SuppressWarnings("serial")
+public class GridScrolling extends AbstractTestUI {
+
+ private Grid grid;
+
+ private IndexedContainer ds;
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected void setup(VaadinRequest request) {
+ // Build data source
+ ds = new IndexedContainer();
+
+ for (int col = 0; col < 5; col++) {
+ ds.addContainerProperty("col" + col, String.class, "");
+ }
+
+ for (int row = 0; row < 65536; row++) {
+ Item item = ds.addItem(Integer.valueOf(row));
+ for (int col = 0; col < 5; col++) {
+ item.getItemProperty("col" + col).setValue(
+ "(" + row + ", " + col + ")");
+ }
+ }
+
+ grid = new Grid(ds);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.addComponent(grid);
+ hl.setMargin(true);
+ hl.setSpacing(true);
+
+ VerticalLayout vl = new VerticalLayout();
+ vl.setSpacing(true);
+
+ // Add scroll buttons
+ Button scrollUpButton = new Button("Top", new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ grid.scrollToStart();
+ }
+ });
+ scrollUpButton.setSizeFull();
+ vl.addComponent(scrollUpButton);
+
+ for (int i = 1; i < 7; ++i) {
+ final int row = (ds.size() / 7) * i;
+ Button scrollButton = new Button("Scroll to row " + row,
+ new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ grid.scrollTo(Integer.valueOf(row),
+ ScrollDestination.MIDDLE);
+ }
+ });
+ scrollButton.setSizeFull();
+ vl.addComponent(scrollButton);
+ }
+
+ Button scrollDownButton = new Button("Bottom", new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ grid.scrollToEnd();
+ }
+ });
+ scrollDownButton.setSizeFull();
+ vl.addComponent(scrollDownButton);
+
+ hl.addComponent(vl);
+ addComponent(hl);
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Test Grid programmatic scrolling features";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 13327;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java
new file mode 100644
index 0000000000..75b83ea3aa
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java
@@ -0,0 +1,59 @@
+/*
+ * 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 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.GridColumn;
+
+public class GridSingleColumn extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+
+ IndexedContainer indexedContainer = new IndexedContainer();
+ indexedContainer.addContainerProperty("column1", String.class, "");
+
+ for (int i = 0; i < 100; i++) {
+ Item addItem = indexedContainer.addItem(i);
+ addItem.getItemProperty("column1").setValue("cell");
+ }
+
+ Grid grid = new Grid(indexedContainer);
+ grid.setSelectionMode(SelectionMode.NONE);
+
+ GridColumn column = grid.getColumn("column1");
+
+ column.setHeaderCaption("Header");
+
+ addComponent(grid);
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Tests a single column grid";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return null;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java
new file mode 100644
index 0000000000..2e062f36c6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.tests.annotations.TestCategory;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+@TestCategory("grid")
+public class GridSingleColumnTest extends MultiBrowserTest {
+
+ /*
+ * TODO unignore once column header captions are reimplemented
+ */
+ @Test
+ @Ignore
+ public void headerIsVisible() {
+ openTestURL();
+
+ WebElement header = getDriver().findElement(
+ By.className("v-grid-header"));
+ WebElement cell = header.findElement(By.className("v-grid-cell"));
+ assertThat(cell.getText(), is("Header"));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java b/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java
new file mode 100644
index 0000000000..ccedcc908a
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java
@@ -0,0 +1,37 @@
+/*
+ * 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 com.vaadin.ui.components.grid.AbstractRenderer;
+
+import elemental.json.Json;
+import elemental.json.JsonArray;
+import elemental.json.JsonValue;
+
+public class IntArrayRenderer extends AbstractRenderer<int[]> {
+ public IntArrayRenderer() {
+ super(int[].class);
+ }
+
+ @Override
+ public JsonValue encode(int[] value) {
+ JsonArray valueArray = Json.createArray();
+ for (int i = 0; i < value.length; ++i) {
+ valueArray.set(i, value[i]);
+ }
+ return valueArray;
+ }
+}
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..41ccddc2cf
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.vaadin.tests.widgetset.client.grid.RowAwareRendererConnector.RowAwareRendererRpc;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.components.grid.AbstractRenderer;
+
+import elemental.json.Json;
+import elemental.json.JsonValue;
+
+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 JsonValue encode(Void value) {
+ return Json.createNull();
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeatures.java
new file mode 100644
index 0000000000..478fa53893
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeatures.java
@@ -0,0 +1,36 @@
+/*
+ * 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.basicfeatures;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.UI;
+
+@Widgetset(TestingWidgetSet.NAME)
+public class EscalatorBasicClientFeatures extends UI {
+
+ public class EscalatorTestComponent extends AbstractComponent {
+ // empty
+ }
+
+ @Override
+ public void init(VaadinRequest request) {
+ setContent(new EscalatorTestComponent());
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java
new file mode 100644
index 0000000000..eff964bd4f
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.basicfeatures;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.Dimension;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.tests.annotations.TestCategory;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+@TestCategory("grid")
+public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest {
+ protected static final String COLUMNS_AND_ROWS = "Columns and Rows";
+
+ protected static final String COLUMNS = "Columns";
+ protected static final String ADD_ONE_COLUMN_TO_BEGINNING = "Add one column to beginning";
+ protected static final String ADD_ONE_ROW_TO_BEGINNING = "Add one row to beginning";
+ protected static final String REMOVE_ONE_COLUMN_FROM_BEGINNING = "Remove one column from beginning";
+ protected static final String REMOVE_ONE_ROW_FROM_BEGINNING = "Remove one row from beginning";
+
+ protected static final String HEADER_ROWS = "Header Rows";
+ protected static final String BODY_ROWS = "Body Rows";
+ protected static final String FOOTER_ROWS = "Footer Rows";
+
+ protected static final String GENERAL = "General";
+ protected static final String POPULATE_COLUMN_ROW = "Populate Escalator (columns, then rows)";
+ protected static final String POPULATE_ROW_COLUMN = "Populate Escalator (rows, then columns)";
+ protected static final String CLEAR_COLUMN_ROW = "Clear (columns, then rows)";
+ protected static final String CLEAR_ROW_COLUMN = "Clear (rows, then columns)";
+
+ protected static final String FEATURES = "Features";
+ protected static final String FROZEN_COLUMNS = "Frozen columns";
+ protected static final String FREEZE_1_COLUMN = "Freeze 1 column";
+ protected static final String FREEZE_0_COLUMNS = "Freeze 0 columns";
+ protected static final String COLUMN_SPANNING = "Column spanning";
+ protected static final String COLSPAN_NORMAL = "Apply normal colspan";
+ protected static final String COLSPAN_NONE = "Apply no colspan";
+
+ @Override
+ protected Class<?> getUIClass() {
+ return EscalatorBasicClientFeatures.class;
+ }
+
+ protected WebElement getEscalator() {
+ return getDriver().findElement(By.className("v-escalator"));
+ }
+
+ protected WebElement getHeaderRow(int row) {
+ return getRow("thead", row);
+ }
+
+ protected WebElement getBodyRow(int row) {
+ return getRow("tbody", row);
+ }
+
+ protected WebElement getFooterRow(int row) {
+ return getRow("tfoot", row);
+ }
+
+ protected WebElement getHeaderCell(int row, int col) {
+ return getCell("thead", row, col);
+ }
+
+ protected WebElement getBodyCell(int row, int col) {
+ return getCell("tbody", row, col);
+ }
+
+ protected WebElement getFooterCell(int row, int col) {
+ return getCell("tfoot", row, col);
+ }
+
+ private WebElement getCell(String sectionTag, int row, int col) {
+ WebElement rowElement = getRow(sectionTag, row);
+ if (rowElement != null) {
+ try {
+ return rowElement.findElement(By.xpath("*[" + (col + 1) + "]"));
+ } catch (NoSuchElementException e) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ private WebElement getRow(String sectionTag, int row) {
+ WebElement escalator = getEscalator();
+ WebElement tableSection = escalator.findElement(By.tagName(sectionTag));
+
+ try {
+ return tableSection.findElement(By.xpath("tr[" + (row + 1) + "]"));
+ } catch (NoSuchElementException e) {
+ return null;
+ }
+ }
+
+ protected void selectMenu(String menuCaption) {
+ WebElement menuElement = getMenuElement(menuCaption);
+ Dimension size = menuElement.getSize();
+ new Actions(getDriver()).moveToElement(menuElement, size.width - 10,
+ size.height / 2).perform();
+ }
+
+ private WebElement getMenuElement(String menuCaption) {
+ return getDriver().findElement(
+ By.xpath("//td[text() = '" + menuCaption + "']"));
+ }
+
+ protected void selectMenuPath(String... menuCaptions) {
+ new Actions(getDriver()).moveToElement(getMenuElement(menuCaptions[0]))
+ .click().perform();
+ for (int i = 1; i < menuCaptions.length - 1; ++i) {
+ selectMenu(menuCaptions[i]);
+ new Actions(getDriver()).moveByOffset(20, 0).perform();
+ }
+ new Actions(getDriver())
+ .moveToElement(
+ getMenuElement(menuCaptions[menuCaptions.length - 1]))
+ .click().perform();
+ }
+
+ protected void assertLogContains(String substring) {
+ assertTrue("log should've contained, but didn't: " + substring,
+ getLogText().contains(substring));
+ }
+
+ protected void assertLogDoesNotContain(String substring) {
+ assertFalse("log shouldn't have contained, but did: " + substring,
+ getLogText().contains(substring));
+ }
+
+ private String getLogText() {
+ WebElement log = getDriver().findElement(By.cssSelector("#log"));
+ return log.getText();
+ }
+
+ protected void assertLogContainsInOrder(String... substrings) {
+ String log = getLogText();
+ int cursor = 0;
+ for (String substring : substrings) {
+ String remainingLog = log.substring(cursor, log.length());
+ int substringIndex = remainingLog.indexOf(substring);
+ if (substringIndex == -1) {
+ fail("substring \"" + substring
+ + "\" was not found in order from log.");
+ }
+
+ cursor += substringIndex + substring.length();
+ }
+ }
+
+ protected void scrollVerticallyTo(int px) {
+ executeScript("arguments[0].scrollTop = " + px, getVeticalScrollbar());
+ }
+
+ private WebElement getVeticalScrollbar() {
+ return getEscalator().findElement(
+ By.className("v-escalator-scroller-vertical"));
+ }
+
+ protected void scrollHorizontallyTo(int px) {
+ executeScript("arguments[0].scrollLeft = " + px,
+ getHorizontalScrollbar());
+ }
+
+ private WebElement getHorizontalScrollbar() {
+ return getEscalator().findElement(
+ By.className("v-escalator-scroller-horizontal"));
+ }
+
+ protected Object executeScript(String script, Object... args) {
+ return ((JavascriptExecutor) getDriver()).executeScript(script, args);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorColspanTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorColspanTest.java
new file mode 100644
index 0000000000..8cbba35faa
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorColspanTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.basicfeatures;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.openqa.selenium.WebElement;
+
+public class EscalatorColspanTest extends EscalatorBasicClientFeaturesTest {
+ private static final int NO_COLSPAN = 1;
+
+ @Test
+ public void testNoColspan() {
+ openTestURL();
+ populate();
+
+ assertEquals(NO_COLSPAN, getColSpan(getHeaderCell(0, 0)));
+ assertEquals(NO_COLSPAN, getColSpan(getBodyCell(0, 0)));
+ assertEquals(NO_COLSPAN, getColSpan(getFooterCell(0, 0)));
+ }
+
+ @Test
+ public void testColspan() {
+ openTestURL();
+ populate();
+
+ int singleCellWidth = getWidth(getBodyCell(0, 0));
+ int doubleCellWidth = singleCellWidth * 2;
+
+ selectMenuPath(FEATURES, COLUMN_SPANNING, COLSPAN_NORMAL);
+
+ WebElement bodyCell = getBodyCell(0, 0);
+ assertEquals(2, getColSpan(bodyCell));
+ assertEquals(doubleCellWidth, getWidth(bodyCell));
+ }
+
+ @Test
+ public void testColspanToggle() {
+ openTestURL();
+ populate();
+
+ int singleCellWidth = getWidth(getBodyCell(0, 0));
+
+ selectMenuPath(FEATURES, COLUMN_SPANNING, COLSPAN_NORMAL);
+ selectMenuPath(FEATURES, COLUMN_SPANNING, COLSPAN_NONE);
+
+ WebElement bodyCell = getBodyCell(0, 0);
+ assertEquals(NO_COLSPAN, getColSpan(bodyCell));
+ assertEquals(singleCellWidth, getWidth(bodyCell));
+ }
+
+ private static int getWidth(WebElement element) {
+ String widthString = element.getCssValue("width"); // e.g. 100px
+ if ("0".equals(widthString)) {
+ return 0;
+ } else if (widthString.endsWith("px")) {
+ return Integer.parseInt(widthString.substring(0,
+ widthString.length() - 2));
+ } else {
+ throw new IllegalStateException("Element width expressed "
+ + "in an unsupported format: " + widthString);
+ }
+ }
+
+ private static int getColSpan(WebElement cell) {
+ String attribute = cell.getAttribute("colspan");
+ if (attribute == null) {
+ return NO_COLSPAN;
+ } else {
+ return Integer.parseInt(attribute);
+ }
+ }
+
+ private void populate() {
+ selectMenuPath(GENERAL, POPULATE_COLUMN_ROW);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorColumnFreezingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorColumnFreezingTest.java
new file mode 100644
index 0000000000..fb217789c2
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorColumnFreezingTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.basicfeatures;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+import org.openqa.selenium.WebElement;
+
+public class EscalatorColumnFreezingTest extends EscalatorBasicClientFeaturesTest {
+
+ private final static Pattern TRANSFORM_PATTERN = Pattern.compile(// @formatter:off
+ // any start of the string
+ ".*"
+
+ // non-capturing group for "webkitTransform: " or "transform: "
+ + "(?:webkitT|t)ransform: "
+
+ // non-capturing group for "translate" or "translate3d"
+ + "translate(?:3d)?"
+
+ // capturing the digits in e.g "(100px,"
+ + "\\((\\d+)px,"
+
+ // any end of the string
+ + ".*");
+
+ // @formatter:on
+
+ private final static Pattern LEFT_PATTERN = Pattern
+ .compile(".*left: (\\d+)px.*");
+
+ private static final int NO_FREEZE = -1;
+
+ @Test
+ public void testNoFreeze() {
+ openTestURL();
+ populate();
+
+ WebElement bodyCell = getBodyCell(0, 0);
+ assertFalse(isFrozen(bodyCell));
+ assertEquals(NO_FREEZE, getFrozenScrollCompensation(bodyCell));
+ }
+
+ @Test
+ public void testOneFreeze() {
+ openTestURL();
+ populate();
+
+ selectMenuPath(FEATURES, FROZEN_COLUMNS, FREEZE_1_COLUMN);
+ int scrollPx = 100;
+ scrollHorizontallyTo(scrollPx);
+
+ WebElement bodyCell = getBodyCell(0, 0);
+ assertTrue(isFrozen(bodyCell));
+ assertEquals(scrollPx, getFrozenScrollCompensation(bodyCell));
+ }
+
+ @Test
+ public void testFreezeToggle() {
+ openTestURL();
+ populate();
+
+ selectMenuPath(FEATURES, FROZEN_COLUMNS, FREEZE_1_COLUMN);
+ scrollHorizontallyTo(100);
+ selectMenuPath(FEATURES, FROZEN_COLUMNS, FREEZE_0_COLUMNS);
+
+ WebElement bodyCell = getBodyCell(0, 0);
+ assertFalse(isFrozen(bodyCell));
+ assertEquals(NO_FREEZE, getFrozenScrollCompensation(bodyCell));
+ }
+
+ private void populate() {
+ selectMenuPath(GENERAL, POPULATE_COLUMN_ROW);
+ }
+
+ private static boolean isFrozen(WebElement cell) {
+ return cell.getAttribute("class").contains("frozen");
+ }
+
+ private static int getFrozenScrollCompensation(WebElement cell) {
+ String styleAttribute = cell.getAttribute("style");
+ Matcher transformMatcher = TRANSFORM_PATTERN.matcher(styleAttribute);
+ Matcher leftMatcher = LEFT_PATTERN.matcher(styleAttribute);
+
+ if (transformMatcher.find()) {
+ return Integer.parseInt(transformMatcher.group(1));
+ } else if (leftMatcher.find()) {
+ return Integer.parseInt(leftMatcher.group(1));
+ } else {
+ return NO_FREEZE;
+ }
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorRowColumnTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorRowColumnTest.java
new file mode 100644
index 0000000000..f45eec07f8
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorRowColumnTest.java
@@ -0,0 +1,203 @@
+/*
+ * 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.basicfeatures;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+
+public class EscalatorRowColumnTest extends EscalatorBasicClientFeaturesTest {
+
+ @Test
+ public void testInit() {
+ openTestURL();
+ assertNotNull(getEscalator());
+ assertNull(getHeaderRow(0));
+ assertNull(getBodyRow(0));
+ assertNull(getFooterRow(0));
+
+ assertLogContains("Columns: 0");
+ assertLogContains("Header rows: 0");
+ assertLogContains("Body rows: 0");
+ assertLogContains("Footer rows: 0");
+ }
+
+ @Test
+ public void testInsertAColumn() {
+ openTestURL();
+
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS, ADD_ONE_COLUMN_TO_BEGINNING);
+ assertNull(getHeaderRow(0));
+ assertNull(getBodyRow(0));
+ assertNull(getFooterRow(0));
+ assertLogContains("Columns: 1");
+ }
+
+ @Test
+ public void testInsertAHeaderRow() {
+ openTestURL();
+
+ selectMenuPath(COLUMNS_AND_ROWS, HEADER_ROWS, ADD_ONE_ROW_TO_BEGINNING);
+ assertNull(getHeaderCell(0, 0));
+ assertNull(getBodyCell(0, 0));
+ assertNull(getFooterCell(0, 0));
+ assertLogContains("Header rows: 1");
+ }
+
+ @Test
+ public void testInsertABodyRow() {
+ openTestURL();
+
+ selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING);
+ assertNull(getHeaderCell(0, 0));
+ assertNull(getBodyCell(0, 0));
+ assertNull(getFooterCell(0, 0));
+ assertLogContains("Body rows: 1");
+ }
+
+ @Test
+ public void testInsertAFooterRow() {
+ openTestURL();
+
+ selectMenuPath(COLUMNS_AND_ROWS, FOOTER_ROWS, ADD_ONE_ROW_TO_BEGINNING);
+ assertNull(getHeaderCell(0, 0));
+ assertNull(getBodyCell(0, 0));
+ assertNull(getFooterCell(0, 0));
+ assertLogContains("Footer rows: 1");
+ }
+
+ @Test
+ public void testInsertAColumnAndAHeaderRow() {
+ openTestURL();
+
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS, ADD_ONE_COLUMN_TO_BEGINNING);
+ selectMenuPath(COLUMNS_AND_ROWS, HEADER_ROWS, ADD_ONE_ROW_TO_BEGINNING);
+ assertNotNull(getHeaderCell(0, 0));
+ assertNull(getBodyCell(0, 0));
+ assertNull(getFooterCell(0, 0));
+ assertLogContains("Columns: 1");
+ assertLogContains("Header rows: 1");
+ }
+
+ @Test
+ public void testInsertAColumnAndABodyRow() {
+ openTestURL();
+
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS, ADD_ONE_COLUMN_TO_BEGINNING);
+ selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING);
+ assertNull(getHeaderCell(0, 0));
+ assertNotNull(getBodyCell(0, 0));
+ assertNull(getFooterCell(0, 0));
+ assertLogContains("Columns: 1");
+ assertLogContains("Body rows: 1");
+ }
+
+ @Test
+ public void testInsertAColumnAndAFooterRow() {
+ openTestURL();
+
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS, ADD_ONE_COLUMN_TO_BEGINNING);
+ selectMenuPath(COLUMNS_AND_ROWS, FOOTER_ROWS, ADD_ONE_ROW_TO_BEGINNING);
+ assertNull(getHeaderCell(0, 0));
+ assertNull(getBodyCell(0, 0));
+ assertNotNull(getFooterCell(0, 0));
+ assertLogContains("Columns: 1");
+ assertLogContains("Footer rows: 1");
+ }
+
+ @Test
+ public void testInsertAHeaderRowAndAColumn() {
+ openTestURL();
+
+ selectMenuPath(COLUMNS_AND_ROWS, HEADER_ROWS, ADD_ONE_ROW_TO_BEGINNING);
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS, ADD_ONE_COLUMN_TO_BEGINNING);
+ assertNotNull(getHeaderCell(0, 0));
+ assertNull(getBodyCell(0, 0));
+ assertNull(getFooterCell(0, 0));
+ assertLogContains("Columns: 1");
+ assertLogContains("Header rows: 1");
+ }
+
+ @Test
+ public void testInsertABodyRowAndAColumn() {
+ openTestURL();
+
+ selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING);
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS, ADD_ONE_COLUMN_TO_BEGINNING);
+ assertNull(getHeaderCell(0, 0));
+ assertNotNull(getBodyCell(0, 0));
+ assertNull(getFooterCell(0, 0));
+ assertLogContains("Columns: 1");
+ assertLogContains("Body rows: 1");
+ }
+
+ @Test
+ public void testInsertAFooterRowAndAColumn() {
+ openTestURL();
+
+ selectMenuPath(COLUMNS_AND_ROWS, FOOTER_ROWS, ADD_ONE_ROW_TO_BEGINNING);
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS, ADD_ONE_COLUMN_TO_BEGINNING);
+ assertNull(getHeaderCell(0, 0));
+ assertNull(getBodyCell(0, 0));
+ assertNotNull(getFooterCell(0, 0));
+ assertLogContains("Columns: 1");
+ assertLogContains("Footer rows: 1");
+ }
+
+ @Test
+ public void testFillColRow() {
+ openTestURL();
+
+ selectMenuPath(GENERAL, POPULATE_COLUMN_ROW);
+ scrollVerticallyTo(2000); // more like 1857, but this should be enough.
+
+ // if not found, an exception is thrown here
+ findElement(By.xpath("//td[text()='Cell: 9,99']"));
+ }
+
+ @Test
+ public void testFillRowCol() {
+ openTestURL();
+
+ selectMenuPath(GENERAL, POPULATE_ROW_COLUMN);
+ scrollVerticallyTo(2000); // more like 1857, but this should be enough.
+
+ // if not found, an exception is thrown here
+ findElement(By.xpath("//td[text()='Cell: 9,99']"));
+ }
+
+ @Test
+ public void testClearColRow() {
+ openTestURL();
+
+ selectMenuPath(GENERAL, POPULATE_COLUMN_ROW);
+ selectMenuPath(GENERAL, CLEAR_COLUMN_ROW);
+
+ assertNull(getBodyCell(0, 0));
+ }
+
+ @Test
+ public void testClearRowCol() {
+ openTestURL();
+
+ selectMenuPath(GENERAL, POPULATE_COLUMN_ROW);
+ selectMenuPath(GENERAL, CLEAR_ROW_COLUMN);
+
+ assertNull(getBodyCell(0, 0));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorUpdaterUi.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorUpdaterUi.java
new file mode 100644
index 0000000000..7e822e41ba
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorUpdaterUi.java
@@ -0,0 +1,35 @@
+/*
+ * 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.basicfeatures;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.UI;
+
+@Widgetset(TestingWidgetSet.NAME)
+public class EscalatorUpdaterUi extends UI {
+
+ public class EscalatorUpdaterTestComponent extends AbstractComponent {
+ // empty
+ }
+
+ @Override
+ protected void init(VaadinRequest request) {
+ setContent(new EscalatorUpdaterTestComponent());
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorUpdaterUiTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorUpdaterUiTest.java
new file mode 100644
index 0000000000..c1c3a31b77
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorUpdaterUiTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.basicfeatures;
+
+import org.junit.Test;
+
+public class EscalatorUpdaterUiTest extends EscalatorBasicClientFeaturesTest {
+ @Override
+ protected Class<?> getUIClass() {
+ return EscalatorUpdaterUi.class;
+ }
+
+ @Test
+ public void testHeaderPaintOrderRowColRowCol() {
+ boolean addColumnFirst = false;
+ boolean removeColumnFirst = false;
+ testPaintOrder(HEADER_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testHeaderPaintOrderRowColColRow() {
+ boolean addColumnFirst = false;
+ boolean removeColumnFirst = true;
+ testPaintOrder(HEADER_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testHeaderPaintOrderColRowColRow() {
+ boolean addColumnFirst = true;
+ boolean removeColumnFirst = true;
+ testPaintOrder(HEADER_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testHeaderPaintOrderColRowRowCol() {
+ boolean addColumnFirst = true;
+ boolean removeColumnFirst = false;
+ testPaintOrder(HEADER_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testBodyPaintOrderRowColRowCol() {
+ boolean addColumnFirst = false;
+ boolean removeColumnFirst = false;
+ testPaintOrder(BODY_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testBodyPaintOrderRowColColRow() {
+ boolean addColumnFirst = false;
+ boolean removeColumnFirst = true;
+ testPaintOrder(BODY_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testBodyPaintOrderColRowColRow() {
+ boolean addColumnFirst = true;
+ boolean removeColumnFirst = true;
+ testPaintOrder(BODY_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testBodyPaintOrderColRowRowCol() {
+ boolean addColumnFirst = true;
+ boolean removeColumnFirst = false;
+ testPaintOrder(BODY_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testFooterPaintOrderRowColRowCol() {
+ boolean addColumnFirst = false;
+ boolean removeColumnFirst = false;
+ testPaintOrder(FOOTER_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testFooterPaintOrderRowColColRow() {
+ boolean addColumnFirst = false;
+ boolean removeColumnFirst = true;
+ testPaintOrder(FOOTER_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testFooterPaintOrderColRowColRow() {
+ boolean addColumnFirst = true;
+ boolean removeColumnFirst = true;
+ testPaintOrder(FOOTER_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ @Test
+ public void testFooterPaintOrderColRowRowCol() {
+ boolean addColumnFirst = true;
+ boolean removeColumnFirst = false;
+ testPaintOrder(FOOTER_ROWS, addColumnFirst, removeColumnFirst);
+ }
+
+ private void testPaintOrder(String tableSection, boolean addColumnFirst,
+ boolean removeColumnFirst) {
+ openTestURL();
+
+ if (addColumnFirst) {
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS,
+ ADD_ONE_COLUMN_TO_BEGINNING);
+ selectMenuPath(COLUMNS_AND_ROWS, tableSection,
+ ADD_ONE_ROW_TO_BEGINNING);
+ } else {
+ selectMenuPath(COLUMNS_AND_ROWS, tableSection,
+ ADD_ONE_ROW_TO_BEGINNING);
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS,
+ ADD_ONE_COLUMN_TO_BEGINNING);
+ }
+
+ assertLogContainsInOrder("preAttach: elementIsAttached == false",
+ "postAttach: elementIsAttached == true",
+ "update: elementIsAttached == true");
+ assertLogDoesNotContain("preDetach");
+ assertLogDoesNotContain("postDetach");
+
+ if (removeColumnFirst) {
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS,
+ REMOVE_ONE_COLUMN_FROM_BEGINNING);
+ selectMenuPath(COLUMNS_AND_ROWS, tableSection,
+ REMOVE_ONE_ROW_FROM_BEGINNING);
+ } else {
+ selectMenuPath(COLUMNS_AND_ROWS, tableSection,
+ REMOVE_ONE_ROW_FROM_BEGINNING);
+ selectMenuPath(COLUMNS_AND_ROWS, COLUMNS,
+ REMOVE_ONE_COLUMN_FROM_BEGINNING);
+ }
+
+ assertLogContainsInOrder("preDetach: elementIsAttached == true",
+ "postDetach: elementIsAttached == false");
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeatures.java
new file mode 100644
index 0000000000..4c5e703b82
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeatures.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.basicfeatures;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.UI;
+
+/**
+ * Initializer shell for GridClientBasicFeatures test application
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+@Widgetset(TestingWidgetSet.NAME)
+public class GridBasicClientFeatures extends UI {
+
+ public class GridTestComponent extends AbstractComponent {
+ }
+
+ @Override
+ protected void init(VaadinRequest request) {
+ setContent(new GridTestComponent());
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java
new file mode 100644
index 0000000000..e3318fe650
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.basicfeatures;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.Dimension;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+/**
+ * Variant of GridBasicFeaturesTest to be used with GridBasicClientFeatures.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public abstract class GridBasicClientFeaturesTest extends GridBasicFeaturesTest {
+
+ @Override
+ protected Class<?> getUIClass() {
+ return GridBasicClientFeatures.class;
+ }
+
+ @Override
+ protected void selectMenu(String menuCaption) {
+ WebElement menuElement = getMenuElement(menuCaption);
+ Dimension size = menuElement.getSize();
+ new Actions(getDriver()).moveToElement(menuElement, size.width - 10,
+ size.height / 2).perform();
+ }
+
+ private WebElement getMenuElement(String menuCaption) {
+ return getDriver().findElement(
+ By.xpath("//td[text() = '" + menuCaption + "']"));
+ }
+
+ @Override
+ protected void selectMenuPath(String... menuCaptions) {
+ new Actions(getDriver()).moveToElement(getMenuElement(menuCaptions[0]))
+ .click().perform();
+ for (int i = 1; i < menuCaptions.length - 1; ++i) {
+ selectMenu(menuCaptions[i]);
+ new Actions(getDriver()).moveByOffset(20, 0).perform();
+ }
+ new Actions(getDriver())
+ .moveToElement(
+ getMenuElement(menuCaptions[menuCaptions.length - 1]))
+ .click().perform();
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
new file mode 100644
index 0000000000..ae8a0d5eb8
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
@@ -0,0 +1,750 @@
+/*
+ * 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.basicfeatures;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Random;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.shared.ui.grid.GridStaticCellType;
+import com.vaadin.shared.ui.grid.HeightMode;
+import com.vaadin.shared.ui.grid.SortDirection;
+import com.vaadin.tests.components.AbstractComponentTest;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.components.grid.Grid;
+import com.vaadin.ui.components.grid.Grid.SelectionMode;
+import com.vaadin.ui.components.grid.GridColumn;
+import com.vaadin.ui.components.grid.GridFooter;
+import com.vaadin.ui.components.grid.GridFooter.FooterCell;
+import com.vaadin.ui.components.grid.GridHeader;
+import com.vaadin.ui.components.grid.GridHeader.HeaderCell;
+import com.vaadin.ui.components.grid.GridHeader.HeaderRow;
+import com.vaadin.ui.components.grid.SortOrderChangeEvent;
+import com.vaadin.ui.components.grid.SortOrderChangeListener;
+import com.vaadin.ui.components.grid.renderers.DateRenderer;
+import com.vaadin.ui.components.grid.renderers.HtmlRenderer;
+import com.vaadin.ui.components.grid.renderers.NumberRenderer;
+import com.vaadin.ui.components.grid.sort.Sort;
+import com.vaadin.ui.components.grid.sort.SortOrder;
+
+/**
+ * Tests the basic features like columns, footers and headers
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class GridBasicFeatures extends AbstractComponentTest<Grid> {
+
+ private static final int MANUALLY_FORMATTED_COLUMNS = 5;
+ public static final int COLUMNS = 12;
+ public static final int ROWS = 1000;
+
+ private int columnGroupRows = 0;
+ private IndexedContainer ds;
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected Grid constructComponent() {
+
+ // Build data source
+ ds = new IndexedContainer() {
+ @Override
+ public List<Object> getItemIds(int startIndex, int numberOfIds) {
+ log("Requested items " + startIndex + " - "
+ + (startIndex + numberOfIds));
+ return super.getItemIds(startIndex, numberOfIds);
+ }
+ };
+
+ {
+ int col = 0;
+ for (; col < COLUMNS - MANUALLY_FORMATTED_COLUMNS; col++) {
+ ds.addContainerProperty(getColumnProperty(col), String.class,
+ "");
+ }
+
+ ds.addContainerProperty(getColumnProperty(col++), Integer.class,
+ Integer.valueOf(0));
+ ds.addContainerProperty(getColumnProperty(col++), Date.class,
+ new Date());
+ ds.addContainerProperty(getColumnProperty(col++), String.class, "");
+
+ // Random numbers
+ ds.addContainerProperty(getColumnProperty(col++), Integer.class, 0);
+ ds.addContainerProperty(getColumnProperty(col++), Integer.class, 0);
+
+ }
+
+ {
+ Random rand = new Random();
+ rand.setSeed(13334);
+ long timestamp = 0;
+ for (int row = 0; row < ROWS; row++) {
+ Item item = ds.addItem(Integer.valueOf(row));
+ int col = 0;
+ for (; col < COLUMNS - MANUALLY_FORMATTED_COLUMNS; col++) {
+ item.getItemProperty(getColumnProperty(col)).setValue(
+ "(" + row + ", " + col + ")");
+ }
+ item.getItemProperty(getColumnProperty(1)).setReadOnly(true);
+
+ item.getItemProperty(getColumnProperty(col++)).setValue(
+ Integer.valueOf(row));
+ item.getItemProperty(getColumnProperty(col++)).setValue(
+ new Date(timestamp));
+ timestamp += 91250000; // a bit over a day, just to get
+ // variation
+ item.getItemProperty(getColumnProperty(col++)).setValue(
+ "<b>" + row + "</b>");
+
+ // Random numbers
+ item.getItemProperty(getColumnProperty(col++)).setValue(
+ rand.nextInt());
+ // Random between 0 - 5 to test multisorting
+ item.getItemProperty(getColumnProperty(col++)).setValue(
+ rand.nextInt(5));
+ }
+ }
+
+ // Create grid
+ Grid grid = new Grid(ds);
+
+ {
+ int col = grid.getContainerDatasource().getContainerPropertyIds()
+ .size()
+ - MANUALLY_FORMATTED_COLUMNS;
+ grid.getColumn(getColumnProperty(col++)).setRenderer(
+ new NumberRenderer(new DecimalFormat("0,000.00",
+ DecimalFormatSymbols.getInstance(new Locale("fi",
+ "FI")))));
+ grid.getColumn(getColumnProperty(col++)).setRenderer(
+ new DateRenderer(new SimpleDateFormat("dd.MM.yy HH:mm")));
+ grid.getColumn(getColumnProperty(col++)).setRenderer(
+ new HtmlRenderer());
+ grid.getColumn(getColumnProperty(col++)).setRenderer(
+ new NumberRenderer());
+ grid.getColumn(getColumnProperty(col++)).setRenderer(
+ new NumberRenderer());
+ }
+
+ // Create footer
+ GridFooter footer = grid.getFooter();
+ footer.appendRow();
+ footer.setVisible(false);
+
+ // Add footer values (header values are automatically created)
+ for (int col = 0; col < COLUMNS; col++) {
+ footer.getRow(0).getCell(getColumnProperty(col))
+ .setText("Footer " + col);
+ }
+
+ // Set varying column widths
+ for (int col = 0; col < COLUMNS; col++) {
+ grid.getColumn(getColumnProperty(col)).setWidth(100 + col * 50);
+ }
+
+ grid.addSortOrderChangeListener(new SortOrderChangeListener() {
+ @Override
+ public void sortOrderChange(SortOrderChangeEvent event) {
+
+ String origin;
+ switch (event.getOriginator()) {
+ case API:
+ origin = "API";
+ break;
+ case INTERNAL:
+ origin = "INTERNAL";
+ break;
+ case USER:
+ origin = "USER";
+ break;
+ default:
+ origin = "!!! ERROR !!!";
+ break;
+ }
+
+ log("Sort order: " + event.getSortOrder() + " by " + origin);
+ }
+ });
+
+ grid.setSelectionMode(SelectionMode.NONE);
+
+ grid.getEditorRow().setPropertyEditable(getColumnProperty(3), false);
+
+ createGridActions();
+
+ createColumnActions();
+
+ createHeaderActions();
+
+ createFooterActions();
+
+ createRowActions();
+
+ createEditorRowActions();
+
+ addHeightActions();
+
+ return grid;
+ }
+
+ protected void createGridActions() {
+ LinkedHashMap<String, String> primaryStyleNames = new LinkedHashMap<String, String>();
+ primaryStyleNames.put("v-grid", "v-grid");
+ primaryStyleNames.put("v-escalator", "v-escalator");
+ primaryStyleNames.put("my-grid", "my-grid");
+
+ createMultiClickAction("Primary style name", "State",
+ primaryStyleNames, new Command<Grid, String>() {
+
+ @Override
+ public void execute(Grid grid, String value, Object data) {
+ grid.setPrimaryStyleName(value);
+
+ }
+ }, primaryStyleNames.get("v-grid"));
+
+ LinkedHashMap<String, SelectionMode> selectionModes = new LinkedHashMap<String, Grid.SelectionMode>();
+ selectionModes.put("single", SelectionMode.SINGLE);
+ selectionModes.put("multi", SelectionMode.MULTI);
+ selectionModes.put("none", SelectionMode.NONE);
+ createSelectAction("Selection mode", "State", selectionModes, "none",
+ new Command<Grid, Grid.SelectionMode>() {
+ @Override
+ public void execute(Grid grid, SelectionMode selectionMode,
+ Object data) {
+ grid.setSelectionMode(selectionMode);
+ }
+ });
+
+ LinkedHashMap<String, List<SortOrder>> sortableProperties = new LinkedHashMap<String, List<SortOrder>>();
+ for (Object propertyId : ds.getSortableContainerPropertyIds()) {
+ sortableProperties.put(propertyId + ", ASC", Sort.by(propertyId)
+ .build());
+ sortableProperties.put(propertyId + ", DESC",
+ Sort.by(propertyId, SortDirection.DESCENDING).build());
+ }
+ createSelectAction("Sort by column", "State", sortableProperties,
+ "Column 9, ascending", new Command<Grid, List<SortOrder>>() {
+ @Override
+ public void execute(Grid grid, List<SortOrder> sortOrder,
+ Object data) {
+ grid.setSortOrder(sortOrder);
+ }
+ });
+ }
+
+ protected void createHeaderActions() {
+ createCategory("Header", null);
+
+ createBooleanAction("Visible", "Header", true,
+ new Command<Grid, Boolean>() {
+
+ @Override
+ public void execute(Grid grid, Boolean value, Object data) {
+ grid.getHeader().setVisible(value);
+ }
+ });
+
+ LinkedHashMap<String, String> defaultRows = new LinkedHashMap<String, String>();
+ defaultRows.put("Top", "Top");
+ defaultRows.put("Bottom", "Bottom");
+ defaultRows.put("Unset", "Unset");
+
+ createMultiClickAction("Default row", "Header", defaultRows,
+ new Command<Grid, String>() {
+
+ @Override
+ public void execute(Grid grid, String value, Object data) {
+ HeaderRow defaultRow = null;
+ GridHeader header = grid.getHeader();
+ if (value.equals("Top")) {
+ defaultRow = header.getRow(0);
+ } else if (value.equals("Bottom")) {
+ defaultRow = header.getRow(header.getRowCount() - 1);
+ }
+ header.setDefaultRow(defaultRow);
+ }
+
+ }, defaultRows.get("Top"));
+
+ createClickAction("Prepend row", "Header", new Command<Grid, Object>() {
+
+ @Override
+ public void execute(Grid grid, Object value, Object data) {
+ grid.getHeader().prependRow();
+ }
+
+ }, null);
+ createClickAction("Append row", "Header", new Command<Grid, Object>() {
+
+ @Override
+ public void execute(Grid grid, Object value, Object data) {
+ grid.getHeader().appendRow();
+ }
+
+ }, null);
+
+ createClickAction("Remove top row", "Header",
+ new Command<Grid, Object>() {
+
+ @Override
+ public void execute(Grid grid, Object value, Object data) {
+ grid.getHeader().removeRow(0);
+ }
+
+ }, null);
+ createClickAction("Remove bottom row", "Header",
+ new Command<Grid, Object>() {
+
+ @Override
+ public void execute(Grid grid, Object value, Object data) {
+ grid.getHeader().removeRow(
+ grid.getHeader().getRowCount() - 1);
+ }
+
+ }, null);
+ }
+
+ protected void createFooterActions() {
+ createCategory("Footer", null);
+
+ createBooleanAction("Visible", "Footer", false,
+ new Command<Grid, Boolean>() {
+
+ @Override
+ public void execute(Grid grid, Boolean value, Object data) {
+ grid.getFooter().setVisible(value);
+ }
+ });
+
+ createClickAction("Prepend row", "Footer", new Command<Grid, Object>() {
+
+ @Override
+ public void execute(Grid grid, Object value, Object data) {
+ grid.getFooter().prependRow();
+ }
+
+ }, null);
+ createClickAction("Append row", "Footer", new Command<Grid, Object>() {
+
+ @Override
+ public void execute(Grid grid, Object value, Object data) {
+ grid.getFooter().appendRow();
+ }
+
+ }, null);
+
+ createClickAction("Remove top row", "Footer",
+ new Command<Grid, Object>() {
+
+ @Override
+ public void execute(Grid grid, Object value, Object data) {
+ grid.getFooter().removeRow(0);
+ }
+
+ }, null);
+ createClickAction("Remove bottom row", "Footer",
+ new Command<Grid, Object>() {
+
+ @Override
+ public void execute(Grid grid, Object value, Object data) {
+ grid.getFooter().removeRow(
+ grid.getFooter().getRowCount() - 1);
+ }
+
+ }, null);
+ }
+
+ protected void createColumnActions() {
+ createCategory("Columns", null);
+
+ for (int c = 0; c < COLUMNS; c++) {
+ createCategory(getColumnProperty(c), "Columns");
+
+ createBooleanAction("Visible", getColumnProperty(c), true,
+ new Command<Grid, Boolean>() {
+
+ @Override
+ public void execute(Grid grid, Boolean value,
+ Object columnIndex) {
+ Object propertyId = getColumnProperty((Integer) columnIndex);
+ GridColumn column = grid.getColumn(propertyId);
+ column.setVisible(!column.isVisible());
+ }
+ }, c);
+
+ createClickAction("Remove", getColumnProperty(c),
+ new Command<Grid, String>() {
+
+ @Override
+ public void execute(Grid grid, String value, Object data) {
+ grid.getContainerDatasource()
+ .removeContainerProperty(
+ getColumnProperty((Integer) data));
+ removeCategory("Column " + data);
+ }
+ }, null, c);
+
+ createClickAction("Freeze", getColumnProperty(c),
+ new Command<Grid, String>() {
+
+ @Override
+ public void execute(Grid grid, String value, Object data) {
+ grid.setLastFrozenPropertyId(getColumnProperty((Integer) data));
+ }
+ }, null, c);
+
+ createBooleanAction("Sortable", getColumnProperty(c), true,
+ new Command<Grid, Boolean>() {
+
+ @Override
+ public void execute(Grid grid, Boolean value,
+ Object columnIndex) {
+ Object propertyId = getColumnProperty((Integer) columnIndex);
+ GridColumn column = grid.getColumn(propertyId);
+ column.setSortable(value);
+ }
+ }, c);
+
+ createCategory("Column " + c + " Width", getColumnProperty(c));
+
+ createClickAction("Auto", "Column " + c + " Width",
+ new Command<Grid, Integer>() {
+
+ @Override
+ public void execute(Grid grid, Integer value,
+ Object columnIndex) {
+ Object propertyId = getColumnProperty((Integer) columnIndex);
+ GridColumn column = grid.getColumn(propertyId);
+ column.setWidthUndefined();
+ }
+ }, -1, c);
+
+ for (int w = 50; w < 300; w += 50) {
+ createClickAction(w + "px", "Column " + c + " Width",
+ new Command<Grid, Integer>() {
+
+ @Override
+ public void execute(Grid grid, Integer value,
+ Object columnIndex) {
+ Object propertyId = getColumnProperty((Integer) columnIndex);
+ GridColumn column = grid.getColumn(propertyId);
+ column.setWidth(value);
+ }
+ }, w, c);
+ }
+
+ LinkedHashMap<String, GridStaticCellType> defaultRows = new LinkedHashMap<String, GridStaticCellType>();
+ defaultRows.put("Text Header", GridStaticCellType.TEXT);
+ defaultRows.put("Html Header ", GridStaticCellType.HTML);
+ defaultRows.put("Widget Header", GridStaticCellType.WIDGET);
+
+ createMultiClickAction("Header Type", getColumnProperty(c),
+ defaultRows, new Command<Grid, GridStaticCellType>() {
+
+ @Override
+ public void execute(Grid grid,
+ GridStaticCellType value, Object columnIndex) {
+ final Object propertyId = getColumnProperty((Integer) columnIndex);
+ final HeaderCell cell = grid.getHeader()
+ .getDefaultRow().getCell(propertyId);
+ switch (value) {
+ case TEXT:
+ cell.setText("Text Header");
+ break;
+ case HTML:
+ cell.setHtml("HTML Header");
+ break;
+ case WIDGET:
+ cell.setComponent(new Button("Button Header",
+ new ClickListener() {
+
+ @Override
+ public void buttonClick(
+ ClickEvent event) {
+ log("Button clicked!");
+ }
+ }));
+ default:
+ break;
+ }
+ }
+
+ }, c);
+
+ defaultRows = new LinkedHashMap<String, GridStaticCellType>();
+ defaultRows.put("Text Footer", GridStaticCellType.TEXT);
+ defaultRows.put("Html Footer", GridStaticCellType.HTML);
+ defaultRows.put("Widget Footer", GridStaticCellType.WIDGET);
+
+ createMultiClickAction("Footer Type", getColumnProperty(c),
+ defaultRows, new Command<Grid, GridStaticCellType>() {
+
+ @Override
+ public void execute(Grid grid,
+ GridStaticCellType value, Object columnIndex) {
+ final Object propertyId = getColumnProperty((Integer) columnIndex);
+ final FooterCell cell = grid.getFooter().getRow(0)
+ .getCell(propertyId);
+ switch (value) {
+ case TEXT:
+ cell.setText("Text Footer");
+ break;
+ case HTML:
+ cell.setHtml("HTML Footer");
+ break;
+ case WIDGET:
+ cell.setComponent(new Button("Button Footer",
+ new ClickListener() {
+
+ @Override
+ public void buttonClick(
+ ClickEvent event) {
+ log("Button clicked!");
+ }
+ }));
+ default:
+ break;
+ }
+ }
+
+ }, c);
+ }
+ }
+
+ private static String getColumnProperty(int c) {
+ return "Column " + c;
+ }
+
+ protected void createRowActions() {
+ createCategory("Body rows", null);
+
+ final Command<Grid, String> newRowCommand = new Command<Grid, String>() {
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ Item item = ds.addItemAt(0, new Object());
+ for (int i = 0; i < COLUMNS; i++) {
+ Class<?> type = ds.getType(getColumnProperty(i));
+ if (String.class.isAssignableFrom(type)) {
+ Property<String> itemProperty = getProperty(item, i);
+ itemProperty.setValue("newcell: " + i);
+ } else if (Integer.class.isAssignableFrom(type)) {
+ Property<Integer> itemProperty = getProperty(item, i);
+ itemProperty.setValue(Integer.valueOf(i));
+ } else {
+ // let the default value be taken implicitly.
+ }
+ }
+ }
+
+ private <T extends Object> Property<T> getProperty(Item item, int i) {
+ @SuppressWarnings("unchecked")
+ Property<T> itemProperty = item
+ .getItemProperty(getColumnProperty(i));
+ return itemProperty;
+ }
+ };
+
+ createClickAction("Add 18 rows", "Body rows",
+ new Command<Grid, String>() {
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ for (int i = 0; i < 18; i++) {
+ newRowCommand.execute(c, value, data);
+ }
+ }
+ }, null);
+
+ createClickAction("Add first row", "Body rows", newRowCommand, null);
+
+ createClickAction("Remove first row", "Body rows",
+ new Command<Grid, String>() {
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ Object firstItemId = ds.getIdByIndex(0);
+ ds.removeItem(firstItemId);
+ }
+ }, null);
+
+ createClickAction("Modify first row (getItemProperty)", "Body rows",
+ new Command<Grid, String>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ Object firstItemId = ds.getIdByIndex(0);
+ Item item = ds.getItem(firstItemId);
+ for (int i = 0; i < COLUMNS; i++) {
+ Property<?> property = item
+ .getItemProperty(getColumnProperty(i));
+ if (property.getType().equals(String.class)) {
+ ((Property<String>) property)
+ .setValue("modified: " + i);
+ }
+ }
+ }
+ }, null);
+
+ createClickAction("Modify first row (getContainerProperty)",
+ "Body rows", new Command<Grid, String>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ Object firstItemId = ds.getIdByIndex(0);
+ for (Object containerPropertyId : ds
+ .getContainerPropertyIds()) {
+ Property<?> property = ds.getContainerProperty(
+ firstItemId, containerPropertyId);
+ if (property.getType().equals(String.class)) {
+ ((Property<String>) property)
+ .setValue("modified: "
+ + containerPropertyId);
+ }
+ }
+ }
+ }, null);
+
+ createBooleanAction("Select first row", "Body rows", false,
+ new Command<Grid, Boolean>() {
+ @Override
+ public void execute(Grid grid, Boolean select, Object data) {
+ final Object firstItemId = grid
+ .getContainerDatasource().firstItemId();
+ if (select.booleanValue()) {
+ grid.select(firstItemId);
+ } else {
+ grid.deselect(firstItemId);
+ }
+ }
+ });
+
+ createClickAction("Remove all rows", "Body rows",
+ new Command<Grid, String>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ ds.removeAllItems();
+ }
+ }, null);
+ }
+
+ protected void createEditorRowActions() {
+ createBooleanAction("Enabled", "Editor row", false,
+ new Command<Grid, Boolean>() {
+ @Override
+ public void execute(Grid c, Boolean value, Object data) {
+ c.getEditorRow().setEnabled(value);
+ }
+ });
+
+ createClickAction("Edit item 5", "Editor row",
+ new Command<Grid, String>() {
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ c.getEditorRow().editItem(5);
+ }
+ }, null);
+
+ createClickAction("Edit item 100", "Editor row",
+ new Command<Grid, String>() {
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ c.getEditorRow().editItem(100);
+ }
+ }, null);
+
+ createClickAction("Cancel edit", "Editor row",
+ new Command<Grid, String>() {
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ c.getEditorRow().cancel();
+ }
+ }, null);
+
+ }
+
+ @SuppressWarnings("boxing")
+ protected void addHeightActions() {
+ createCategory("Height by Rows", "Size");
+
+ createBooleanAction("HeightMode Row", "Size", false,
+ new Command<Grid, Boolean>() {
+ @Override
+ public void execute(Grid c, Boolean heightModeByRows,
+ Object data) {
+ c.setHeightMode(heightModeByRows ? HeightMode.ROW
+ : HeightMode.CSS);
+ }
+ }, null);
+
+ addActionForHeightByRows(1d / 3d);
+ addActionForHeightByRows(2d / 3d);
+
+ for (double i = 1; i < 5; i++) {
+ addActionForHeightByRows(i);
+ addActionForHeightByRows(i + 1d / 3d);
+ addActionForHeightByRows(i + 2d / 3d);
+ }
+
+ Command<Grid, String> sizeCommand = new Command<Grid, String>() {
+ @Override
+ public void execute(Grid grid, String height, Object data) {
+ grid.setHeight(height);
+ }
+ };
+
+ createCategory("Height", "Size");
+ // header 20px + scrollbar 16px = 36px baseline
+ createClickAction("86px (no drag scroll select)", "Height",
+ sizeCommand, "86px");
+ createClickAction("96px (drag scroll select limit)", "Height",
+ sizeCommand, "96px");
+ createClickAction("106px (drag scroll select enabled)", "Height",
+ sizeCommand, "106px");
+ }
+
+ private void addActionForHeightByRows(final Double i) {
+ DecimalFormat df = new DecimalFormat("0.00");
+ createClickAction(df.format(i) + " rows", "Height by Rows",
+ new Command<Grid, String>() {
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ c.setHeightByRows(i);
+ }
+ }, null);
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 12829;
+ }
+
+ @Override
+ protected Class<Grid> getTestClass() {
+ return Grid.class;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java
new file mode 100644
index 0000000000..56f5f63c39
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.basicfeatures;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.remote.DesiredCapabilities;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.tests.annotations.TestCategory;
+import com.vaadin.tests.components.grid.GridElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+@TestCategory("grid")
+public abstract class GridBasicFeaturesTest extends MultiBrowserTest {
+
+ @Override
+ protected DesiredCapabilities getDesiredCapabilities() {
+ DesiredCapabilities dCap = super.getDesiredCapabilities();
+ if (BrowserUtil.isIE(dCap)) {
+ dCap.setCapability("requireWindowFocus", true);
+ }
+ return super.getDesiredCapabilities();
+ }
+
+ @Override
+ protected Class<?> getUIClass() {
+ return GridBasicFeatures.class;
+ }
+
+ protected void selectSubMenu(String menuCaption) {
+ selectMenu(menuCaption);
+ new Actions(getDriver()).moveByOffset(100, 0).build().perform();
+ }
+
+ protected void selectMenu(String menuCaption) {
+ getDriver().findElement(
+ By.xpath("//span[text() = '" + menuCaption + "']")).click();
+ }
+
+ protected void selectMenuPath(String... menuCaptions) {
+ selectMenu(menuCaptions[0]);
+ for (int i = 1; i < menuCaptions.length; i++) {
+ selectSubMenu(menuCaptions[i]);
+ }
+ }
+
+ protected GridElement getGridElement() {
+ return ((TestBenchElement) findElement(By.id("testComponent")))
+ .wrap(GridElement.class);
+ }
+
+ protected void scrollGridVerticallyTo(double px) {
+ executeScript("arguments[0].scrollTop = " + px,
+ getGridVerticalScrollbar());
+ }
+
+ protected List<TestBenchElement> getGridHeaderRowCells() {
+ List<TestBenchElement> headerCells = new ArrayList<TestBenchElement>();
+ for (int i = 0; i < getGridElement().getHeaderCount(); ++i) {
+ headerCells.addAll(getGridElement().getHeaderCells(i));
+ }
+ return headerCells;
+ }
+
+ protected List<TestBenchElement> getGridFooterRowCells() {
+ List<TestBenchElement> footerCells = new ArrayList<TestBenchElement>();
+ for (int i = 0; i < getGridElement().getFooterCount(); ++i) {
+ footerCells.addAll(getGridElement().getFooterCells(i));
+ }
+ return footerCells;
+ }
+
+ protected WebElement getEditorRow() {
+ List<WebElement> elems = getGridElement().findElements(
+ By.className("v-grid-editor-row"));
+
+ assertLessThanOrEqual("number of editor rows", elems.size(), 1);
+
+ return elems.isEmpty() ? null : elems.get(0);
+ }
+
+ private Object executeScript(String script, WebElement element) {
+ final WebDriver driver = getDriver();
+ if (driver instanceof JavascriptExecutor) {
+ final JavascriptExecutor je = (JavascriptExecutor) driver;
+ return je.executeScript(script, element);
+ } else {
+ throw new IllegalStateException("current driver "
+ + getDriver().getClass().getName() + " is not a "
+ + JavascriptExecutor.class.getSimpleName());
+ }
+ }
+
+ protected WebElement getGridVerticalScrollbar() {
+ return getDriver()
+ .findElement(
+ By.xpath("//div[contains(@class, \"v-grid-scroller-vertical\")]"));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientColumnPropertiesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientColumnPropertiesTest.java
new file mode 100644
index 0000000000..ea46ee24a5
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientColumnPropertiesTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.basicfeatures.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest;
+import com.vaadin.tests.widgetset.client.grid.GridBasicClientFeaturesWidget;
+
+public class GridClientColumnPropertiesTest extends GridBasicClientFeaturesTest {
+
+ @Test
+ public void initialColumnWidths() {
+ openTestURL();
+
+ for (int col = 0; col < GridBasicClientFeaturesWidget.COLUMNS; col++) {
+ int width = getGridElement().getCell(0, col).getSize().getWidth();
+ if (col <= 6) {
+ // Growing column widths
+ assertEquals(50 + col * 25, width);
+ } else {
+ assertEquals(100, width);
+ }
+ }
+ }
+
+ @Test
+ public void testChangingColumnWidth() {
+ openTestURL();
+
+ selectMenuPath("Component", "Columns", "Column 0", "Width", "50px");
+ int width = getGridElement().getCell(0, 0).getSize().getWidth();
+ assertEquals(50, width);
+
+ selectMenuPath("Component", "Columns", "Column 0", "Width", "200px");
+ width = getGridElement().getCell(0, 0).getSize().getWidth();
+ assertEquals(200, width);
+
+ selectMenuPath("Component", "Columns", "Column 0", "Width", "auto");
+ width = getGridElement().getCell(0, 0).getSize().getWidth();
+ assertEquals(100, width);
+ }
+
+ @Test
+ public void testFrozenColumns() {
+ openTestURL();
+
+ assertFalse(cellIsFrozen(0, 0));
+ assertFalse(cellIsFrozen(0, 1));
+
+ selectMenuPath("Component", "Columns", "Column 0", "Frozen");
+
+ assertTrue(cellIsFrozen(1, 0));
+ assertFalse(cellIsFrozen(1, 1));
+ }
+
+ private boolean cellIsFrozen(int row, int col) {
+ return getGridElement().getCell(row, col).isFrozen();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientKeyEventsTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientKeyEventsTest.java
new file mode 100644
index 0000000000..47bd9f6cb7
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientKeyEventsTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.basicfeatures.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.testbench.By;
+import com.vaadin.tests.components.grid.GridElement.GridCellElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest;
+
+public class GridClientKeyEventsTest extends GridBasicClientFeaturesTest {
+
+ private List<String> eventOrder = Arrays.asList("keydown", "keyup",
+ "keypress");
+
+ @Test
+ public void testBodyKeyEvents() throws IOException {
+ openTestURL();
+
+ getGridElement().getCell(2, 2).click();
+
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ for (int i = 0; i < 3; ++i) {
+ assertEquals("Body key event handler was not called.", "(2, 2) "
+ + eventOrder.get(i) + " 13",
+ findElements(By.className("v-label")).get(i * 3).getText());
+
+ assertTrue("Header key event handler got called unexpectedly.",
+ findElements(By.className("v-label")).get(i * 3 + 1)
+ .getText().isEmpty());
+ assertTrue("Footer key event handler got called unexpectedly.",
+ findElements(By.className("v-label")).get(i * 3 + 2)
+ .getText().isEmpty());
+ }
+
+ }
+
+ @Test
+ public void testHeaderKeyEvents() throws IOException {
+ openTestURL();
+
+ getGridElement().getHeaderCell(0, 2).click();
+
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ for (int i = 0; i < 3; ++i) {
+ assertEquals("Header key event handler was not called.", "(0, 2) "
+ + eventOrder.get(i) + " 13",
+ findElements(By.className("v-label")).get(i * 3 + 1)
+ .getText());
+
+ assertTrue("Body key event handler got called unexpectedly.",
+ findElements(By.className("v-label")).get(i * 3).getText()
+ .isEmpty());
+ assertTrue("Footer key event handler got called unexpectedly.",
+ findElements(By.className("v-label")).get(i * 3 + 2)
+ .getText().isEmpty());
+ }
+ }
+
+ @Test
+ public void testFooterKeyEvents() throws IOException {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Append row");
+ getGridElement().getFooterCell(0, 2).click();
+
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ for (int i = 0; i < 3; ++i) {
+ assertEquals("Footer key event handler was not called.", "(0, 2) "
+ + eventOrder.get(i) + " 13",
+ findElements(By.className("v-label")).get(i * 3 + 2)
+ .getText());
+
+ assertTrue("Body key event handler got called unexpectedly.",
+ findElements(By.className("v-label")).get(i * 3).getText()
+ .isEmpty());
+ assertTrue("Header key event handler got called unexpectedly.",
+ findElements(By.className("v-label")).get(i * 3 + 1)
+ .getText().isEmpty());
+
+ }
+ }
+
+ @Test
+ public void testNoKeyEventsFromWidget() {
+ openTestURL();
+
+ selectMenuPath("Component", "Columns", "Column 2", "Header Type",
+ "Widget Header");
+ GridCellElement header = getGridElement().getHeaderCell(0, 2);
+ header.findElement(By.tagName("button")).click();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ for (int i = 0; i < 3; ++i) {
+ assertTrue("Header key event handler got called unexpectedly.",
+ findElements(By.className("v-label")).get(i * 3 + 1)
+ .getText().isEmpty());
+
+ }
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java
new file mode 100644
index 0000000000..4b47837887
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.basicfeatures.client;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest;
+
+public class GridClientSelectionTest extends GridBasicClientFeaturesTest {
+
+ @Test
+ public void testChangeSelectionMode() {
+ openTestURL();
+
+ selectMenuPath("Component", "State", "Selection mode", "none");
+ assertTrue("First column was selection column", getGridElement()
+ .getCell(0, 0).getText().equals("(0, 0)"));
+ selectMenuPath("Component", "State", "Selection mode", "multi");
+ assertTrue("First column was not selection column", getGridElement()
+ .getCell(0, 1).getText().equals("(0, 0)"));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java
new file mode 100644
index 0000000000..4c64eac6e5
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.basicfeatures.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
+
+public class GridEditorRowClientTest extends GridBasicClientFeaturesTest {
+
+ @Before
+ public void setUp() {
+ openTestURL();
+ selectMenuPath("Component", "Editor row", "Enabled");
+ }
+
+ @Test
+ public void testProgrammaticOpeningClosing() {
+ selectMenuPath("Component", "Editor row", "Edit row 5");
+ assertNotNull(getEditorRow());
+
+ selectMenuPath("Component", "Editor row", "Cancel edit");
+ assertNull(getEditorRow());
+ assertEquals("Row 5 edit cancelled",
+ findElement(By.className("editor-row-log")).getText());
+ }
+
+ @Test
+ public void testProgrammaticOpeningWithScroll() {
+ selectMenuPath("Component", "Editor row", "Edit row 100");
+ assertNotNull(getEditorRow());
+ }
+
+ @Test(expected = NoSuchElementException.class)
+ public void testVerticalScrollLocking() {
+ selectMenuPath("Component", "Editor row", "Edit row 5");
+ getGridElement().getCell(200, 0);
+ }
+
+ @Test
+ public void testKeyboardOpeningClosing() {
+
+ getGridElement().getCell(4, 0).click();
+
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ assertNotNull(getEditorRow());
+
+ new Actions(getDriver()).sendKeys(Keys.ESCAPE).perform();
+ assertNull(getEditorRow());
+ assertEquals("Row 4 edit cancelled",
+ findElement(By.className("editor-row-log")).getText());
+
+ // Disable editor row
+ selectMenuPath("Component", "Editor row", "Enabled");
+
+ getGridElement().getCell(5, 0).click();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+ assertNull(getEditorRow());
+ }
+
+ @Test
+ public void testWidgetBinding() throws Exception {
+ selectMenuPath("Component", "Editor row", "Edit row 100");
+ WebElement editorRow = getEditorRow();
+
+ List<WebElement> widgets = editorRow.findElements(By
+ .className("gwt-TextBox"));
+
+ assertEquals(GridBasicFeatures.COLUMNS, widgets.size());
+
+ assertEquals("(100, 0)", widgets.get(0).getAttribute("value"));
+ assertEquals("(100, 1)", widgets.get(1).getAttribute("value"));
+ assertEquals("(100, 2)", widgets.get(2).getAttribute("value"));
+
+ assertEquals("100", widgets.get(7).getAttribute("value"));
+ assertEquals("<b>100</b>", widgets.get(9).getAttribute("value"));
+ }
+
+ @Test
+ public void testWithSelectionColumn() throws Exception {
+ selectMenuPath("Component", "State", "Selection mode", "multi");
+ selectMenuPath("Component", "State", "Editor row", "Edit row 5");
+
+ WebElement editorRow = getEditorRow();
+ List<WebElement> selectorDivs = editorRow.findElements(By
+ .cssSelector("div"));
+
+ assertTrue("selector column cell should've been empty", selectorDivs
+ .get(0).getAttribute("innerHTML").isEmpty());
+ assertFalse("normal column cell shoul've had contents", selectorDivs
+ .get(1).getAttribute("innerHTML").isEmpty());
+ }
+
+ @Test
+ public void testCommit() {
+ selectMenuPath("Component", "Editor row", "Edit row 100");
+
+ List<WebElement> widgets = getEditorRow().findElements(
+ By.className("gwt-TextBox"));
+
+ widgets.get(0).sendKeys(" changed");
+
+ WebElement saveButton = getEditorRow().findElement(
+ By.className("v-editor-row-save"));
+
+ saveButton.click();
+
+ assertEquals("(100, 0) changed", getGridElement().getCell(100, 0)
+ .getText());
+ }
+
+ @Test
+ public void testDiscard() {
+ selectMenuPath("Component", "Editor row", "Edit row 100");
+
+ List<WebElement> widgets = getEditorRow().findElements(
+ By.className("gwt-TextBox"));
+
+ widgets.get(0).sendKeys(" changed");
+
+ selectMenuPath("Component", "Editor row", "Discard");
+
+ assertEquals("(100, 0)", getGridElement().getCell(100, 0).getText());
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java
new file mode 100644
index 0000000000..7ca3894060
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.basicfeatures.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+public class GridEditorRowTest extends GridBasicFeaturesTest {
+
+ @Before
+ public void setUp() {
+ openTestURL();
+ selectMenuPath("Component", "Editor row", "Enabled");
+ }
+
+ @Test
+ public void testProgrammaticOpeningClosing() {
+ selectMenuPath("Component", "Editor row", "Edit item 5");
+ assertNotNull(getEditorRow());
+
+ selectMenuPath("Component", "Editor row", "Cancel edit");
+ assertNull(getEditorRow());
+ }
+
+ @Test
+ public void testProgrammaticOpeningWhenDisabled() {
+ selectMenuPath("Component", "Editor row", "Enabled");
+ selectMenuPath("Component", "Editor row", "Edit item 5");
+ assertNull(getEditorRow());
+ assertEquals(
+ "4. Exception occured, java.lang.IllegalStateExceptionThis EditorRow is not enabled",
+ getLogRow(0));
+ }
+
+ @Test
+ public void testDisablingWhileOpen() {
+ selectMenuPath("Component", "Editor row", "Edit item 5");
+ selectMenuPath("Component", "Editor row", "Enabled");
+ assertNotNull(getEditorRow());
+ assertEquals(
+ "4. Exception occured, java.lang.IllegalStateExceptionCannot disable the editor row while an item (5) is being edited.",
+ getLogRow(0));
+
+ }
+
+ @Test
+ public void testProgrammaticOpeningWithScroll() {
+ selectMenuPath("Component", "Editor row", "Edit item 100");
+ assertNotNull(getEditorRow());
+ }
+
+ @Test(expected = NoSuchElementException.class)
+ public void testVerticalScrollLocking() {
+ selectMenuPath("Component", "Editor row", "Edit item 5");
+ getGridElement().getCell(200, 0);
+ }
+
+ @Test
+ public void testKeyboardOpeningClosing() {
+
+ getGridElement().getCell(4, 0).click();
+
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ assertNotNull(getEditorRow());
+
+ new Actions(getDriver()).sendKeys(Keys.ESCAPE).perform();
+ assertNull(getEditorRow());
+
+ // Disable editor row
+ selectMenuPath("Component", "Editor row", "Enabled");
+
+ getGridElement().getCell(5, 0).click();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+ assertNull(getEditorRow());
+ }
+
+ @Test
+ public void testComponentBinding() {
+ selectMenuPath("Component", "State", "Editor row", "Edit item 100");
+
+ List<WebElement> widgets = getEditorRow().findElements(
+ By.className("v-widget"));
+
+ assertEquals(GridBasicFeatures.COLUMNS, widgets.size());
+
+ assertEquals("(100, 0)", widgets.get(0).getAttribute("value"));
+ assertEquals("(100, 1)", widgets.get(1).getAttribute("value"));
+ assertEquals("(100, 2)", widgets.get(2).getAttribute("value"));
+ assertEquals("<b>100</b>", widgets.get(9).getAttribute("value"));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridFooterTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridFooterTest.java
new file mode 100644
index 0000000000..8124e5361f
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridFooterTest.java
@@ -0,0 +1,207 @@
+/*
+ * 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.basicfeatures.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.tests.components.grid.GridElement.GridCellElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
+
+public class GridFooterTest extends GridStaticSectionTest {
+
+ @Test
+ public void testDefaultFooter() {
+ openTestURL();
+
+ // Footer should have zero rows by default
+ assertFooterCount(0);
+ }
+
+ @Test
+ public void testFooterVisibility() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Visible");
+
+ assertFooterCount(0);
+
+ selectMenuPath("Component", "Footer", "Append row");
+
+ assertFooterCount(0);
+
+ selectMenuPath("Component", "Footer", "Visible");
+
+ assertFooterCount(1);
+ }
+
+ @Test
+ public void testAddRows() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Append row");
+
+ assertFooterCount(1);
+ assertFooterTexts(0, 0);
+
+ selectMenuPath("Component", "Footer", "Prepend row");
+
+ assertFooterCount(2);
+ assertFooterTexts(1, 0);
+ assertFooterTexts(0, 1);
+
+ selectMenuPath("Component", "Footer", "Append row");
+
+ assertFooterCount(3);
+ assertFooterTexts(1, 0);
+ assertFooterTexts(0, 1);
+ assertFooterTexts(2, 2);
+ }
+
+ @Test
+ public void testRemoveRows() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Prepend row");
+ selectMenuPath("Component", "Footer", "Append row");
+
+ selectMenuPath("Component", "Footer", "Remove top row");
+
+ assertFooterCount(1);
+ assertFooterTexts(1, 0);
+
+ selectMenuPath("Component", "Footer", "Remove bottom row");
+ assertFooterCount(0);
+ }
+
+ @Test
+ public void joinColumnsByCells() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Append row");
+
+ selectMenuPath("Component", "Footer", "Row 1", "Join column cells 0, 1");
+
+ GridCellElement spannedCell = getGridElement().getFooterCell(0, 0);
+ assertTrue(spannedCell.isDisplayed());
+ assertEquals("2", spannedCell.getAttribute("colspan"));
+
+ GridCellElement hiddenCell = getGridElement().getFooterCell(0, 1);
+ assertFalse(hiddenCell.isDisplayed());
+ }
+
+ @Test
+ public void joinColumnsByColumns() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Append row");
+
+ selectMenuPath("Component", "Footer", "Row 1", "Join columns 1, 2");
+
+ GridCellElement spannedCell = getGridElement().getFooterCell(0, 1);
+ assertTrue(spannedCell.isDisplayed());
+ assertEquals("2", spannedCell.getAttribute("colspan"));
+
+ GridCellElement hiddenCell = getGridElement().getFooterCell(0, 2);
+ assertFalse(hiddenCell.isDisplayed());
+ }
+
+ @Test
+ public void joinAllColumnsInRow() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Append row");
+
+ selectMenuPath("Component", "Footer", "Row 1", "Join all columns");
+
+ GridCellElement spannedCell = getGridElement().getFooterCell(0, 0);
+ assertTrue(spannedCell.isDisplayed());
+ assertEquals("" + GridBasicFeatures.COLUMNS,
+ spannedCell.getAttribute("colspan"));
+
+ for (int columnIndex = 1; columnIndex < GridBasicFeatures.COLUMNS; columnIndex++) {
+ GridCellElement hiddenCell = getGridElement().getFooterCell(0,
+ columnIndex);
+ assertFalse(hiddenCell.isDisplayed());
+ }
+ }
+
+ @Test
+ public void testInitialCellTypes() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Append row");
+
+ GridCellElement textCell = getGridElement().getFooterCell(0, 0);
+ assertEquals("Footer (0,0)", textCell.getText());
+
+ GridCellElement widgetCell = getGridElement().getFooterCell(0, 1);
+ assertTrue(widgetCell.isElementPresent(By.className("gwt-HTML")));
+
+ GridCellElement htmlCell = getGridElement().getFooterCell(0, 2);
+ assertHTML("<b>Footer (0,2)</b>", htmlCell);
+ }
+
+ @Test
+ public void testDynamicallyChangingCellType() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Append row");
+
+ selectMenuPath("Component", "Columns", "Column 0", "Footer Type",
+ "Widget Footer");
+ GridCellElement widgetCell = getGridElement().getFooterCell(0, 0);
+ assertTrue(widgetCell.isElementPresent(By.className("gwt-Button")));
+
+ selectMenuPath("Component", "Columns", "Column 1", "Footer Type",
+ "HTML Footer");
+ GridCellElement htmlCell = getGridElement().getFooterCell(0, 1);
+ assertHTML("<b>HTML Footer</b>", htmlCell);
+
+ selectMenuPath("Component", "Columns", "Column 2", "Footer Type",
+ "Text Footer");
+ GridCellElement textCell = getGridElement().getFooterCell(0, 2);
+ assertEquals("Text Footer", textCell.getText());
+ }
+
+ @Test
+ public void testCellWidgetInteraction() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Append row");
+
+ selectMenuPath("Component", "Columns", "Column 0", "Footer Type",
+ "Widget Footer");
+ GridCellElement widgetCell = getGridElement().getFooterCell(0, 0);
+ WebElement button = widgetCell.findElement(By.className("gwt-Button"));
+
+ assertNotEquals("Clicked", button.getText());
+
+ button.click();
+
+ assertEquals("Clicked", button.getText());
+ }
+
+ private void assertFooterCount(int count) {
+ assertEquals("footer count", count, getGridElement().getFooterCount());
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridHeaderTest.java
new file mode 100644
index 0000000000..c528571a2e
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridHeaderTest.java
@@ -0,0 +1,359 @@
+/*
+ * 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.basicfeatures.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.tests.components.grid.GridElement.GridCellElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
+
+public class GridHeaderTest extends GridStaticSectionTest {
+
+ @Test
+ public void testDefaultHeader() throws Exception {
+ openTestURL();
+
+ assertHeaderCount(1);
+ assertHeaderTexts(0, 0);
+ }
+
+ @Test
+ public void testHeaderVisibility() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Header", "Visible");
+
+ assertHeaderCount(0);
+
+ selectMenuPath("Component", "Header", "Append row");
+
+ assertHeaderCount(0);
+
+ selectMenuPath("Component", "Header", "Visible");
+
+ assertHeaderCount(2);
+ }
+
+ @Test
+ public void testHeaderCaptions() throws Exception {
+ openTestURL();
+
+ assertHeaderTexts(0, 0);
+ }
+
+ @Test
+ public void testHeadersWithInvisibleColumns() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Columns", "Column 1", "Visible");
+ selectMenuPath("Component", "Columns", "Column 3", "Visible");
+
+ List<TestBenchElement> cells = getGridHeaderRowCells();
+ assertEquals(GridBasicFeatures.COLUMNS - 2, cells.size());
+
+ assertText("Header (0,0)", cells.get(0));
+ assertHTML("<b>Header (0,2)</b>", cells.get(1));
+ assertHTML("<b>Header (0,4)</b>", cells.get(2));
+
+ selectMenuPath("Component", "Columns", "Column 3", "Visible");
+
+ cells = getGridHeaderRowCells();
+ assertEquals(GridBasicFeatures.COLUMNS - 1, cells.size());
+
+ assertText("Header (0,0)", cells.get(0));
+ assertHTML("<b>Header (0,2)</b>", cells.get(1));
+ assertText("Header (0,3)", cells.get(2));
+ assertHTML("<b>Header (0,4)</b>", cells.get(3));
+ }
+
+ @Test
+ public void testAddRows() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Header", "Append row");
+
+ assertHeaderCount(2);
+ assertHeaderTexts(0, 0);
+ assertHeaderTexts(1, 1);
+
+ selectMenuPath("Component", "Header", "Prepend row");
+
+ assertHeaderCount(3);
+ assertHeaderTexts(2, 0);
+ assertHeaderTexts(0, 1);
+ assertHeaderTexts(1, 2);
+
+ selectMenuPath("Component", "Header", "Append row");
+
+ assertHeaderCount(4);
+ assertHeaderTexts(2, 0);
+ assertHeaderTexts(0, 1);
+ assertHeaderTexts(1, 2);
+ assertHeaderTexts(3, 3);
+ }
+
+ @Test
+ public void testRemoveRows() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Header", "Prepend row");
+ selectMenuPath("Component", "Header", "Append row");
+
+ selectMenuPath("Component", "Header", "Remove top row");
+
+ assertHeaderCount(2);
+ assertHeaderTexts(0, 0);
+ assertHeaderTexts(2, 1);
+
+ selectMenuPath("Component", "Header", "Remove bottom row");
+ assertHeaderCount(1);
+ assertHeaderTexts(0, 0);
+ }
+
+ @Test
+ public void testDefaultRow() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Columns", "Column 0", "Sortable");
+
+ GridCellElement headerCell = getGridElement().getHeaderCell(0, 0);
+
+ headerCell.click();
+
+ assertTrue(hasClassName(headerCell, "sort-asc"));
+
+ headerCell.click();
+
+ assertFalse(hasClassName(headerCell, "sort-asc"));
+ assertTrue(hasClassName(headerCell, "sort-desc"));
+
+ selectMenuPath("Component", "Header", "Prepend row");
+ selectMenuPath("Component", "Header", "Default row", "Top");
+
+ assertFalse(hasClassName(headerCell, "sort-desc"));
+ headerCell = getGridElement().getHeaderCell(0, 0);
+ assertTrue(hasClassName(headerCell, "sort-desc"));
+
+ selectMenuPath("Component", "Header", "Default row", "Unset");
+
+ assertFalse(hasClassName(headerCell, "sort-desc"));
+ }
+
+ @Test
+ public void joinHeaderColumnsByCells() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Header", "Append row");
+
+ selectMenuPath("Component", "Header", "Row 2", "Join column cells 0, 1");
+
+ GridCellElement spannedCell = getGridElement().getHeaderCell(1, 0);
+ assertTrue(spannedCell.isDisplayed());
+ assertEquals("2", spannedCell.getAttribute("colspan"));
+
+ GridCellElement hiddenCell = getGridElement().getHeaderCell(1, 1);
+ assertFalse(hiddenCell.isDisplayed());
+ }
+
+ @Test
+ public void joinHeaderColumnsByColumns() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Header", "Append row");
+
+ selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2");
+
+ GridCellElement spannedCell = getGridElement().getHeaderCell(1, 1);
+ assertTrue(spannedCell.isDisplayed());
+ assertEquals("2", spannedCell.getAttribute("colspan"));
+
+ GridCellElement hiddenCell = getGridElement().getHeaderCell(1, 2);
+ assertFalse(hiddenCell.isDisplayed());
+ }
+
+ @Test
+ public void joinAllColumnsInHeaderRow() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Header", "Append row");
+
+ selectMenuPath("Component", "Header", "Row 2", "Join all columns");
+
+ GridCellElement spannedCell = getGridElement().getHeaderCell(1, 0);
+ assertTrue(spannedCell.isDisplayed());
+ assertEquals("" + GridBasicFeatures.COLUMNS,
+ spannedCell.getAttribute("colspan"));
+
+ for (int columnIndex = 1; columnIndex < GridBasicFeatures.COLUMNS; columnIndex++) {
+ GridCellElement hiddenCell = getGridElement().getHeaderCell(1,
+ columnIndex);
+ assertFalse(hiddenCell.isDisplayed());
+ }
+ }
+
+ @Test
+ public void hideFirstColumnInColspan() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Header", "Append row");
+
+ selectMenuPath("Component", "Header", "Row 2", "Join all columns");
+
+ int visibleColumns = GridBasicFeatures.COLUMNS;
+
+ GridCellElement spannedCell = getGridElement().getHeaderCell(1, 0);
+ assertTrue(spannedCell.isDisplayed());
+ assertEquals("" + visibleColumns, spannedCell.getAttribute("colspan"));
+
+ selectMenuPath("Component", "Columns", "Column 0", "Visible");
+ visibleColumns--;
+
+ spannedCell = getGridElement().getHeaderCell(1, 0);
+ assertTrue(spannedCell.isDisplayed());
+ assertEquals("" + visibleColumns, spannedCell.getAttribute("colspan"));
+ }
+
+ @Test
+ public void multipleColspanAndMultipleHiddenColumns() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Header", "Append row");
+
+ // Join columns [1,2] and [3,4,5]
+ selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2");
+ GridCellElement spannedCell = getGridElement().getHeaderCell(1, 1);
+ assertEquals("2", spannedCell.getAttribute("colspan"));
+
+ selectMenuPath("Component", "Header", "Row 2", "Join columns 3, 4, 5");
+ spannedCell = getGridElement().getHeaderCell(1, 3);
+ assertEquals("3", spannedCell.getAttribute("colspan"));
+
+ selectMenuPath("Component", "Columns", "Column 2", "Visible");
+ spannedCell = getGridElement().getHeaderCell(1, 1);
+ assertEquals("1", spannedCell.getAttribute("colspan"));
+
+ // Ensure the second colspan is preserved (shifts one index to the left)
+ spannedCell = getGridElement().getHeaderCell(1, 2);
+ assertEquals("3", spannedCell.getAttribute("colspan"));
+
+ selectMenuPath("Component", "Columns", "Column 4", "Visible");
+
+ // First reduced colspan is reduced
+ spannedCell = getGridElement().getHeaderCell(1, 1);
+ assertEquals("1", spannedCell.getAttribute("colspan"));
+
+ // Second colspan is also now reduced
+ spannedCell = getGridElement().getHeaderCell(1, 2);
+ assertEquals("2", spannedCell.getAttribute("colspan"));
+
+ // Show columns again
+ selectMenuPath("Component", "Columns", "Column 2", "Visible");
+ selectMenuPath("Component", "Columns", "Column 4", "Visible");
+
+ spannedCell = getGridElement().getHeaderCell(1, 1);
+ assertEquals("2", spannedCell.getAttribute("colspan"));
+ spannedCell = getGridElement().getHeaderCell(1, 3);
+ assertEquals("3", spannedCell.getAttribute("colspan"));
+
+ }
+
+ @Test
+ public void testInitialCellTypes() throws Exception {
+ openTestURL();
+
+ GridCellElement textCell = getGridElement().getHeaderCell(0, 0);
+ assertEquals("Header (0,0)", textCell.getText());
+
+ GridCellElement widgetCell = getGridElement().getHeaderCell(0, 1);
+ assertTrue(widgetCell.isElementPresent(By.className("gwt-HTML")));
+
+ GridCellElement htmlCell = getGridElement().getHeaderCell(0, 2);
+ assertHTML("<b>Header (0,2)</b>", htmlCell);
+ }
+
+ @Test
+ public void testDynamicallyChangingCellType() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Columns", "Column 0", "Header Type",
+ "Widget Header");
+ GridCellElement widgetCell = getGridElement().getHeaderCell(0, 0);
+ assertTrue(widgetCell.isElementPresent(By.className("gwt-Button")));
+
+ selectMenuPath("Component", "Columns", "Column 1", "Header Type",
+ "HTML Header");
+ GridCellElement htmlCell = getGridElement().getHeaderCell(0, 1);
+ assertHTML("<b>HTML Header</b>", htmlCell);
+
+ selectMenuPath("Component", "Columns", "Column 2", "Header Type",
+ "Text Header");
+ GridCellElement textCell = getGridElement().getHeaderCell(0, 2);
+ assertEquals("Text Header", textCell.getText());
+ }
+
+ @Test
+ public void testCellWidgetInteraction() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Columns", "Column 0", "Header Type",
+ "Widget Header");
+ GridCellElement widgetCell = getGridElement().getHeaderCell(0, 0);
+ WebElement button = widgetCell.findElement(By.className("gwt-Button"));
+
+ button.click();
+
+ assertEquals("Clicked", button.getText());
+ }
+
+ @Test
+ public void widgetInSortableCellInteraction() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Columns", "Column 0", "Header Type",
+ "Widget Header");
+
+ selectMenuPath("Component", "Columns", "Column 0", "Sortable");
+
+ GridCellElement widgetCell = getGridElement().getHeaderCell(0, 0);
+ WebElement button = widgetCell.findElement(By.className("gwt-Button"));
+
+ assertNotEquals("Clicked", button.getText());
+
+ button.click();
+
+ assertEquals("Clicked", button.getText());
+ }
+
+ private void assertHeaderCount(int count) {
+ assertEquals("header count", count, getGridElement().getHeaderCount());
+ }
+
+ private boolean hasClassName(TestBenchElement element, String name) {
+ return Arrays.asList(element.getAttribute("class").split(" "))
+ .contains(name);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridStaticSectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridStaticSectionTest.java
new file mode 100644
index 0000000000..cc801bf870
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridStaticSectionTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.basicfeatures.client;
+
+import static org.junit.Assert.assertEquals;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
+
+/**
+ * Abstract base class for header and footer tests.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public abstract class GridStaticSectionTest extends GridBasicClientFeaturesTest {
+
+ protected void assertHeaderTexts(int headerId, int rowIndex) {
+ int i = 0;
+ for (TestBenchElement cell : getGridElement().getHeaderCells(rowIndex)) {
+
+ if (i % 3 == 0) {
+ assertText(String.format("Header (%d,%d)", headerId, i), cell);
+ } else if (i % 2 == 0) {
+ assertHTML(String.format("<b>Header (%d,%d)</b>", headerId, i),
+ cell);
+ } else {
+ assertHTML(String.format(
+ "<div class=\"gwt-HTML\">Header (%d,%d)</div>",
+ headerId, i), cell);
+ }
+
+ i++;
+ }
+ assertEquals("number of header columns", GridBasicFeatures.COLUMNS, i);
+ }
+
+ protected void assertFooterTexts(int footerId, int rowIndex) {
+ int i = 0;
+ for (TestBenchElement cell : getGridElement().getFooterCells(rowIndex)) {
+ if (i % 3 == 0) {
+ assertText(String.format("Footer (%d,%d)", footerId, i), cell);
+ } else if (i % 2 == 0) {
+ assertHTML(String.format("<b>Footer (%d,%d)</b>", footerId, i),
+ cell);
+ } else {
+ assertHTML(String.format(
+ "<div class=\"gwt-HTML\">Footer (%d,%d)</div>",
+ footerId, i), cell);
+ }
+ i++;
+ }
+ assertEquals("number of footer columns", GridBasicFeatures.COLUMNS, i);
+ }
+
+ protected static void assertText(String text, TestBenchElement e) {
+ // TBE.getText returns "" if the element is scrolled out of view
+ assertEquals(text, e.getAttribute("innerHTML"));
+ }
+
+ protected static void assertHTML(String text, TestBenchElement e) {
+ String html = e.getAttribute("innerHTML");
+
+ // IE 8 returns tags as upper case while other browsers do not, make the
+ // comparison non-casesensive
+ html = html.toLowerCase();
+ text = text.toLowerCase();
+
+ // IE 8 returns attributes without quotes, make the comparison without
+ // quotes
+ html = html.replaceAll("\"", "");
+ text = html.replaceAll("\"", "");
+
+ assertEquals(text, html);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridStylingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridStylingTest.java
new file mode 100644
index 0000000000..67e974bd0a
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridStylingTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.basicfeatures.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.vaadin.testbench.By;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
+
+public class GridStylingTest extends GridStaticSectionTest {
+
+ @Test
+ public void testGridPrimaryStyle() throws Exception {
+ openTestURL();
+
+ validateStylenames("v-grid");
+ }
+
+ @Test
+ public void testChangingPrimaryStyleName() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "State", "Primary Stylename",
+ "v-custom-style");
+
+ validateStylenames("v-custom-style");
+ }
+
+ private void validateStylenames(String stylename) {
+
+ String classNames = getGridElement().getAttribute("class");
+ assertEquals(stylename, classNames);
+
+ classNames = getGridElement().getVerticalScroller().getAttribute(
+ "class");
+ assertTrue(classNames.contains(stylename + "-scroller"));
+ assertTrue(classNames.contains(stylename + "-scroller-vertical"));
+
+ classNames = getGridElement().getHorizontalScroller().getAttribute(
+ "class");
+ assertTrue(classNames.contains(stylename + "-scroller"));
+ assertTrue(classNames.contains(stylename + "-scroller-horizontal"));
+
+ classNames = getGridElement().getTableWrapper().getAttribute("class");
+ assertEquals(stylename + "-tablewrapper", classNames);
+
+ classNames = getGridElement().getHeader().getAttribute("class");
+ assertEquals(stylename + "-header", classNames);
+
+ for (int row = 0; row < getGridElement().getHeaderCount(); row++) {
+ classNames = getGridElement().getHeaderRow(row).getAttribute(
+ "class");
+ assertEquals(stylename + "-row", classNames);
+
+ for (int col = 0; col < GridBasicFeatures.COLUMNS; col++) {
+ classNames = getGridElement().getHeaderCell(row, col)
+ .getAttribute("class");
+ assertTrue(classNames.contains(stylename + "-cell"));
+
+ if (row == 0 && col == 0) {
+ assertTrue(classNames,
+ classNames.contains(stylename + "-header-active"));
+ }
+ }
+ }
+
+ classNames = getGridElement().getBody().getAttribute("class");
+ assertEquals(stylename + "-body", classNames);
+
+ int rowsInBody = getGridElement().getBody()
+ .findElements(By.tagName("tr")).size();
+ for (int row = 0; row < rowsInBody; row++) {
+ classNames = getGridElement().getRow(row).getAttribute("class");
+ assertTrue(classNames.contains(stylename + "-row"));
+ assertTrue(classNames.contains(stylename + "-row-has-data"));
+
+ for (int col = 0; col < GridBasicFeatures.COLUMNS; col++) {
+ classNames = getGridElement().getCell(row, col).getAttribute(
+ "class");
+ assertTrue(classNames.contains(stylename + "-cell"));
+
+ if (row == 0 && col == 0) {
+ assertTrue(classNames.contains(stylename + "-cell-active"));
+ }
+ }
+ }
+
+ classNames = getGridElement().getFooter().getAttribute("class");
+ assertEquals(stylename + "-footer", classNames);
+
+ for (int row = 0; row < getGridElement().getFooterCount(); row++) {
+ classNames = getGridElement().getFooterRow(row).getAttribute(
+ "class");
+ assertEquals(stylename + "-row", classNames);
+
+ for (int col = 0; col < GridBasicFeatures.COLUMNS; col++) {
+ classNames = getGridElement().getFooterCell(row, col)
+ .getAttribute("class");
+ assertTrue(classNames.contains(stylename + "-cell"));
+ }
+ }
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridActiveCellAdjustmentTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridActiveCellAdjustmentTest.java
new file mode 100644
index 0000000000..4fef839d2b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridActiveCellAdjustmentTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.basicfeatures.server;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.vaadin.tests.components.grid.GridElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+public class GridActiveCellAdjustmentTest extends GridBasicFeaturesTest {
+
+ @Test
+ public void testActiveCellWithAddAndRemoveRows() {
+ openTestURL();
+ GridElement grid = getGridElement();
+
+ grid.getCell(0, 0).click();
+
+ selectMenuPath("Component", "Body rows", "Add first row");
+ assertTrue("Active cell was not moved when adding a row",
+ grid.getCell(1, 0).isActive());
+
+ selectMenuPath("Component", "Body rows", "Add 18 rows");
+ assertTrue("Active cell was not moved when adding multiple rows", grid
+ .getCell(19, 0).isActive());
+
+ for (int i = 18; i <= 0; --i) {
+ selectMenuPath("Component", "Body rows", "Remove first row");
+ assertTrue("Active cell was not moved when removing a row", grid
+ .getCell(i, 0).isActive());
+ }
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridKeyboardNavigationTest.java
new file mode 100644
index 0000000000..0f9fd875d8
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridKeyboardNavigationTest.java
@@ -0,0 +1,225 @@
+/*
+ * 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.basicfeatures.server;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.tests.components.grid.GridElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+public class GridKeyboardNavigationTest extends GridBasicFeaturesTest {
+
+ @Test
+ public void testCellActiveOnClick() {
+ openTestURL();
+
+ GridElement grid = getGridElement();
+ assertTrue("Body cell 0, 0 is not active on init.", grid.getCell(0, 0)
+ .isActive());
+ grid.getCell(5, 2).click();
+ assertFalse("Body cell 0, 0 was still active after clicking", grid
+ .getCell(0, 0).isActive());
+ assertTrue("Body cell 5, 2 is not active after clicking",
+ grid.getCell(5, 2).isActive());
+ }
+
+ @Test
+ public void testCellNotActiveWhenRendererHandlesEvent() {
+ openTestURL();
+
+ GridElement grid = getGridElement();
+ assertTrue("Body cell 0, 0 is not active on init.", grid.getCell(0, 0)
+ .isActive());
+ grid.getHeaderCell(0, 3).click();
+ assertFalse("Body cell 0, 0 is active after click on header.", grid
+ .getCell(0, 0).isActive());
+ assertTrue("Header cell 0, 3 is not active after click on header.",
+ grid.getHeaderCell(0, 3).isActive());
+ }
+
+ @Test
+ public void testSimpleKeyboardNavigation() {
+ openTestURL();
+
+ GridElement grid = getGridElement();
+ grid.getCell(0, 0).click();
+
+ new Actions(getDriver()).sendKeys(Keys.ARROW_DOWN).perform();
+ assertTrue("Body cell 1, 0 is not active after keyboard navigation.",
+ grid.getCell(1, 0).isActive());
+
+ new Actions(getDriver()).sendKeys(Keys.ARROW_RIGHT).perform();
+ assertTrue("Body cell 1, 1 is not active after keyboard navigation.",
+ grid.getCell(1, 1).isActive());
+
+ int i;
+ for (i = 1; i < 40; ++i) {
+ new Actions(getDriver()).sendKeys(Keys.ARROW_DOWN).perform();
+ }
+
+ assertFalse("Grid has not scrolled with active cell",
+ isElementPresent(By.xpath("//td[text() = '(0, 0)']")));
+ assertTrue("Active cell is not visible",
+ isElementPresent(By.xpath("//td[text() = '(" + i + ", 0)']")));
+ assertTrue("Body cell " + i + ", 1 is not active", grid.getCell(i, 1)
+ .isActive());
+ }
+
+ @Test
+ public void testNavigateFromHeaderToBody() {
+ openTestURL();
+
+ GridElement grid = getGridElement();
+ grid.scrollToRow(300);
+ new Actions(driver).moveToElement(grid.getHeaderCell(0, 7)).click()
+ .perform();
+ grid.scrollToRow(280);
+
+ assertTrue("Header cell is not active.", grid.getHeaderCell(0, 7)
+ .isActive());
+ new Actions(getDriver()).sendKeys(Keys.ARROW_DOWN).perform();
+ assertTrue("Body cell 280, 7 is not active", grid.getCell(280, 7)
+ .isActive());
+ }
+
+ @Test
+ public void testNavigationFromFooterToBody() {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Visible");
+
+ GridElement grid = getGridElement();
+ grid.scrollToRow(300);
+ grid.getFooterCell(0, 2).click();
+
+ assertTrue("Footer cell is not active.", grid.getFooterCell(0, 2)
+ .isActive());
+ new Actions(getDriver()).sendKeys(Keys.ARROW_UP).perform();
+ assertTrue("Body cell 300, 2 is not active", grid.getCell(300, 2)
+ .isActive());
+ }
+
+ @Test
+ public void testNavigateBetweenHeaderAndBodyWithTab() {
+ openTestURL();
+
+ GridElement grid = getGridElement();
+ grid.getCell(10, 2).click();
+
+ assertTrue("Body cell 10, 2 is not active", grid.getCell(10, 2)
+ .isActive());
+ new Actions(getDriver()).keyDown(Keys.SHIFT).sendKeys(Keys.TAB)
+ .keyUp(Keys.SHIFT).perform();
+ assertTrue("Header cell 0, 2 is not active", grid.getHeaderCell(0, 2)
+ .isActive());
+ new Actions(getDriver()).sendKeys(Keys.TAB).perform();
+ assertTrue("Body cell 10, 2 is not active", grid.getCell(10, 2)
+ .isActive());
+
+ // Navigate out of the Grid and try to navigate with arrow keys.
+ new Actions(getDriver()).keyDown(Keys.SHIFT).sendKeys(Keys.TAB)
+ .sendKeys(Keys.TAB).keyUp(Keys.SHIFT).sendKeys(Keys.ARROW_DOWN)
+ .perform();
+ assertTrue("Header cell 0, 2 is not active", grid.getHeaderCell(0, 2)
+ .isActive());
+ }
+
+ @Test
+ public void testNavigateBetweenFooterAndBodyWithTab() {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Visible");
+
+ GridElement grid = getGridElement();
+ grid.getCell(10, 2).click();
+
+ assertTrue("Body cell 10, 2 is not active", grid.getCell(10, 2)
+ .isActive());
+ new Actions(getDriver()).sendKeys(Keys.TAB).perform();
+ assertTrue("Footer cell 0, 2 is not active", grid.getFooterCell(0, 2)
+ .isActive());
+ new Actions(getDriver()).keyDown(Keys.SHIFT).sendKeys(Keys.TAB)
+ .keyUp(Keys.SHIFT).perform();
+ assertTrue("Body cell 10, 2 is not active", grid.getCell(10, 2)
+ .isActive());
+
+ // Navigate out of the Grid and try to navigate with arrow keys.
+ new Actions(getDriver()).sendKeys(Keys.TAB).sendKeys(Keys.TAB)
+ .sendKeys(Keys.ARROW_UP).perform();
+ assertTrue("Footer cell 0, 2 is not active", grid.getFooterCell(0, 2)
+ .isActive());
+ }
+
+ @Test
+ public void testHomeEnd() throws Exception {
+ openTestURL();
+
+ getGridElement().getCell(100, 2).click();
+
+ new Actions(getDriver()).sendKeys(Keys.HOME).perform();
+ assertTrue("First row is not visible", getGridElement().getCell(0, 2)
+ .isDisplayed());
+
+ new Actions(getDriver()).sendKeys(Keys.END).perform();
+ assertTrue("Last row cell not visible",
+ getGridElement().getCell(GridBasicFeatures.ROWS - 1, 2)
+ .isDisplayed());
+ }
+
+ @Test
+ public void testPageUpPageDown() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Size", "HeightMode Row");
+
+ getGridElement().getCell(5, 2).click();
+
+ new Actions(getDriver()).sendKeys(Keys.PAGE_DOWN).perform();
+ assertTrue("Row 5 did not remain active", getGridElement()
+ .getCell(5, 2).isActive());
+ assertTrue("Row 20 did not become visible",
+ getGridElement().getCell(20, 2).isDisplayed());
+
+ new Actions(getDriver()).sendKeys(Keys.PAGE_DOWN).perform();
+ assertTrue("Row 5 did not remain active", getGridElement()
+ .getCell(5, 2).isActive());
+ assertTrue("Row 40 did not become visible",
+ getGridElement().getCell(40, 2).isDisplayed());
+
+ getGridElement().getCell(50, 2).click();
+
+ new Actions(getDriver()).sendKeys(Keys.PAGE_UP).perform();
+ assertTrue("Row 50 did not remain active",
+ getGridElement().getCell(50, 2).isActive());
+ assertTrue("Row 20 did not become visible",
+ getGridElement().getCell(20, 2).isDisplayed());
+
+ new Actions(getDriver()).sendKeys(Keys.PAGE_UP).perform();
+ assertTrue("Row 50 did not remain active",
+ getGridElement().getCell(50, 2).isActive());
+ assertTrue("Row 0 did not become visible",
+ getGridElement().getCell(0, 2).isDisplayed());
+
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java
new file mode 100644
index 0000000000..6e2ac91df2
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java
@@ -0,0 +1,179 @@
+/*
+ * 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.basicfeatures.server;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.tests.components.grid.GridElement;
+import com.vaadin.tests.components.grid.GridElement.GridRowElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+public class GridSelectionTest extends GridBasicFeaturesTest {
+
+ @Test
+ public void testSelectOnOff() throws Exception {
+ openTestURL();
+
+ setSelectionModelMulti();
+
+ assertFalse("row shouldn't start out as selected", getRow(0)
+ .isSelected());
+ toggleFirstRowSelection();
+ assertTrue("row should become selected", getRow(0).isSelected());
+ toggleFirstRowSelection();
+ assertFalse("row shouldn't remain selected", getRow(0).isSelected());
+ }
+
+ @Test
+ public void testSelectOnScrollOffScroll() throws Exception {
+ openTestURL();
+
+ setSelectionModelMulti();
+
+ assertFalse("row shouldn't start out as selected", getRow(0)
+ .isSelected());
+ toggleFirstRowSelection();
+ assertTrue("row should become selected", getRow(0).isSelected());
+
+ scrollGridVerticallyTo(10000); // make sure the row is out of cache
+ scrollGridVerticallyTo(0); // scroll it back into view
+
+ assertTrue("row should still be selected when scrolling "
+ + "back into view", getRow(0).isSelected());
+ }
+
+ @Test
+ public void testSelectScrollOnScrollOff() throws Exception {
+ openTestURL();
+
+ setSelectionModelMulti();
+
+ assertFalse("row shouldn't start out as selected", getRow(0)
+ .isSelected());
+
+ scrollGridVerticallyTo(10000); // make sure the row is out of cache
+ toggleFirstRowSelection();
+
+ scrollGridVerticallyTo(0); // scroll it back into view
+ assertTrue("row should still be selected when scrolling "
+ + "back into view", getRow(0).isSelected());
+
+ toggleFirstRowSelection();
+ assertFalse("row shouldn't remain selected", getRow(0).isSelected());
+ }
+
+ @Test
+ public void testSelectScrollOnOffScroll() throws Exception {
+ openTestURL();
+
+ setSelectionModelMulti();
+
+ assertFalse("row shouldn't start out as selected", getRow(0)
+ .isSelected());
+
+ scrollGridVerticallyTo(10000); // make sure the row is out of cache
+ toggleFirstRowSelection();
+ toggleFirstRowSelection();
+
+ scrollGridVerticallyTo(0); // make sure the row is out of cache
+ assertFalse("row shouldn't be selected when scrolling "
+ + "back into view", getRow(0).isSelected());
+ }
+
+ @Test
+ public void testSingleSelectionUpdatesFromServer() {
+ openTestURL();
+ setSelectionModelSingle();
+
+ GridElement grid = getGridElement();
+ assertFalse("First row was selected from start", grid.getRow(0)
+ .isSelected());
+ toggleFirstRowSelection();
+ assertTrue("First row was not selected.", getRow(0).isSelected());
+ grid.getCell(5, 0).click();
+ assertTrue("Fifth row was not selected.", getRow(5).isSelected());
+ assertFalse("First row was still selected.", getRow(0).isSelected());
+ grid.getCell(0, 0).click();
+ toggleFirstRowSelection();
+ assertFalse("First row was still selected.", getRow(0).isSelected());
+ assertFalse("Fifth row was still selected.", getRow(5).isSelected());
+
+ grid.scrollToRow(600);
+ grid.getCell(595, 0).click();
+ assertTrue("Row 595 was not selected.", getRow(595).isSelected());
+ toggleFirstRowSelection();
+ assertFalse("Row 595 was still selected.", getRow(595).isSelected());
+ assertTrue("First row was not selected.", getRow(0).isSelected());
+ }
+
+ @Test
+ public void testKeyboardSelection() {
+ openTestURL();
+ setSelectionModelMulti();
+
+ GridElement grid = getGridElement();
+ grid.getCell(3, 1).click();
+ new Actions(getDriver()).sendKeys(Keys.SPACE).perform();
+
+ assertTrue("Grid row 3 was not selected with space key.", grid
+ .getRow(3).isSelected());
+
+ new Actions(getDriver()).sendKeys(Keys.SPACE).perform();
+
+ assertTrue("Grid row 3 was not deselected with space key.", !grid
+ .getRow(3).isSelected());
+
+ grid.scrollToRow(500);
+
+ new Actions(getDriver()).sendKeys(Keys.SPACE).perform();
+
+ assertTrue("Grid row 3 was not selected with space key.", grid
+ .getRow(3).isSelected());
+
+ }
+
+ private void setSelectionModelMulti() {
+ selectMenuPath("Component", "State", "Selection mode", "multi");
+ }
+
+ private void setSelectionModelSingle() {
+ selectMenuPath("Component", "State", "Selection mode", "single");
+ }
+
+ @SuppressWarnings("static-method")
+ private boolean isSelected(TestBenchElement row) {
+ /*
+ * FIXME We probably should get a GridRow instead of a plain
+ * TestBenchElement, that has an "isSelected" thing integrated. (henrik
+ * paul 26.6.2014)
+ */
+ return row.getAttribute("class").contains("-row-selected");
+ }
+
+ private void toggleFirstRowSelection() {
+ selectMenuPath("Component", "Body rows", "Select first row");
+ }
+
+ private GridRowElement getRow(int i) {
+ return getGridElement().getRow(i);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java
new file mode 100644
index 0000000000..acc5bfe51a
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java
@@ -0,0 +1,273 @@
+/*
+ * 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.basicfeatures.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.tests.components.grid.GridElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+public class GridSortingTest extends GridBasicFeaturesTest {
+
+ @Test
+ public void testProgrammaticSorting() throws IOException {
+ openTestURL();
+
+ GridElement grid = getGridElement();
+
+ // Sorting by column 9 is sorting by row index that is represented as a
+ // String.
+ // First cells for first 3 rows are (9, 0), (99, 0) and (999, 0)
+ sortBy("Column 9, DESC");
+
+ // Verify that programmatic sorting calls are identified as originating
+ // from API
+ assertEquals("3. Sort order: [Column 9 DESCENDING] by API",
+ getLogRow(0));
+
+ assertTrue("Column 9 should have the sort-desc stylename", grid
+ .getHeaderCell(0, 9).getAttribute("class")
+ .contains("sort-desc"));
+
+ String row = "";
+ for (int i = 0; i < 3; ++i) {
+ row += "9";
+ assertEquals(
+ "Grid is not sorted by Column 9 using descending direction.",
+ "(" + row + ", 0)", grid.getCell(i, 0).getText());
+ }
+
+ // Column 10 is random numbers from Random with seed 13334
+ sortBy("Column 10, ASC");
+
+ assertFalse(
+ "Column 9 should no longer have the sort-desc stylename",
+ grid.getHeaderCell(0, 9).getAttribute("class")
+ .contains("sort-desc"));
+ assertTrue("Column 10 should have the sort-asc stylename", grid
+ .getHeaderCell(0, 10).getAttribute("class")
+ .contains("sort-asc"));
+
+ // Not cleaning up correctly causes exceptions when scrolling.
+ grid.scrollToRow(50);
+ assertFalse("Scrolling caused and exception when shuffled.",
+ getLogRow(0).contains("Exception"));
+
+ for (int i = 0; i < 5; ++i) {
+ assertGreater(
+ "Grid is not sorted by Column 10 using ascending direction",
+ Integer.parseInt(grid.getCell(i + 1, 10).getText()),
+ Integer.parseInt(grid.getCell(i, 10).getText()));
+
+ }
+
+ // Column 7 is row index as a number. Last three row are original rows
+ // 2, 1 and 0.
+ sortBy("Column 7, DESC");
+ for (int i = 0; i < 3; ++i) {
+ assertEquals(
+ "Grid is not sorted by Column 7 using descending direction",
+ "(" + i + ", 0)",
+ grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText());
+ }
+
+ assertFalse(
+ "Column 10 should no longer have the sort-asc stylename",
+ grid.getHeaderCell(0, 10).getAttribute("class")
+ .contains("sort-asc"));
+ assertTrue("Column 7 should have the sort-desc stylename", grid
+ .getHeaderCell(0, 7).getAttribute("class")
+ .contains("sort-desc"));
+
+ }
+
+ @Test
+ public void testUserSorting() throws InterruptedException {
+ openTestURL();
+
+ GridElement grid = getGridElement();
+
+ // Sorting by column 9 is sorting by row index that is represented as a
+ // String.
+ // First cells for first 3 rows are (9, 0), (99, 0) and (999, 0)
+
+ // Click header twice to sort descending
+ grid.getHeaderCell(0, 9).click();
+ grid.getHeaderCell(0, 9).click();
+ String row = "";
+ for (int i = 0; i < 3; ++i) {
+ row += "9";
+ assertEquals(
+ "Grid is not sorted by Column 9 using descending direction.",
+ "(" + row + ", 0)", grid.getCell(i, 0).getText());
+ }
+
+ assertEquals("2. Sort order: [Column 9 ASCENDING] by USER",
+ getLogRow(2));
+ assertEquals("4. Sort order: [Column 9 DESCENDING] by USER",
+ getLogRow(0));
+
+ // Column 10 is random numbers from Random with seed 13334
+ // Click header to sort ascending
+ grid.getHeaderCell(0, 10).click();
+
+ assertEquals("6. Sort order: [Column 10 ASCENDING] by USER",
+ getLogRow(0));
+
+ // Not cleaning up correctly causes exceptions when scrolling.
+ grid.scrollToRow(50);
+ assertFalse("Scrolling caused and exception when shuffled.",
+ getLogRow(0).contains("Exception"));
+
+ for (int i = 0; i < 5; ++i) {
+ assertGreater(
+ "Grid is not sorted by Column 10 using ascending direction",
+ Integer.parseInt(grid.getCell(i + 1, 10).getText()),
+ Integer.parseInt(grid.getCell(i, 10).getText()));
+
+ }
+
+ // Column 7 is row index as a number. Last three row are original rows
+ // 2, 1 and 0.
+ // Click header twice to sort descending
+ grid.getHeaderCell(0, 7).click();
+ grid.getHeaderCell(0, 7).click();
+ for (int i = 0; i < 3; ++i) {
+ assertEquals(
+ "Grid is not sorted by Column 7 using descending direction",
+ "(" + i + ", 0)",
+ grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText());
+ }
+
+ assertEquals("9. Sort order: [Column 7 ASCENDING] by USER",
+ getLogRow(3));
+ assertEquals("11. Sort order: [Column 7 DESCENDING] by USER",
+ getLogRow(1));
+ }
+
+ @Test
+ public void testUserMultiColumnSorting() {
+ openTestURL();
+
+ getGridElement().getHeaderCell(0, 0).click();
+ new Actions(driver).keyDown(Keys.SHIFT).perform();
+ getGridElement().getHeaderCell(0, 11).click();
+ new Actions(driver).keyUp(Keys.SHIFT).perform();
+
+ String prev = getGridElement().getCell(0, 11).getAttribute("innerHTML");
+ for (int i = 1; i <= 6; ++i) {
+ assertEquals("Column 11 should contain same values.", prev,
+ getGridElement().getCell(i, 11).getAttribute("innerHTML"));
+ }
+
+ prev = getGridElement().getCell(0, 0).getText();
+ for (int i = 1; i <= 6; ++i) {
+ assertTrue(
+ "Grid is not sorted by column 0.",
+ prev.compareTo(getGridElement().getCell(i, 0).getText()) < 0);
+ }
+
+ }
+
+ private void sendKeys(CharSequence... seq) {
+ new Actions(getDriver()).sendKeys(seq).perform();
+ }
+
+ private void holdKey(Keys key) {
+ new Actions(getDriver()).keyDown(key).perform();
+ }
+
+ private void releaseKey(Keys key) {
+ new Actions(getDriver()).keyUp(key).perform();
+ }
+
+ private void assertLog(String expected) {
+ assertEquals(expected, getLogRow(0));
+ }
+
+ @Test
+ public void testKeyboardSorting() {
+ openTestURL();
+
+ //
+ // NOTE: This is a work-around to get the focus to the first header
+ // cell.
+ // We can't use element.focus() because TestBench (or, rather, Selenium
+ // beneath it) has rather interesting bugs regarding focus handling.
+ //
+ getGridElement().getCell(0, 0).click();
+ sendKeys(Keys.ARROW_UP);
+
+ // Sort ASCENDING on first column
+ sendKeys(Keys.ENTER);
+ assertLog("2. Sort order: [Column 0 ASCENDING] by USER");
+
+ // Move to next column
+ sendKeys(Keys.RIGHT);
+
+ // Add this column to the existing sorting group
+ holdKey(Keys.SHIFT);
+ sendKeys(Keys.ENTER);
+ releaseKey(Keys.SHIFT);
+ assertLog("4. Sort order: [Column 0 ASCENDING, Column 1 ASCENDING] by USER");
+
+ // Move to next column
+ sendKeys(Keys.RIGHT);
+
+ // Add a third column to the sorting group
+ holdKey(Keys.SHIFT);
+ sendKeys(Keys.ENTER);
+ releaseKey(Keys.SHIFT);
+ assertLog("6. Sort order: [Column 0 ASCENDING, Column 1 ASCENDING, Column 2 ASCENDING] by USER");
+
+ // Move back to the second column
+ sendKeys(Keys.LEFT);
+
+ // Change sort direction of the second column to DESCENDING
+ holdKey(Keys.SHIFT);
+ sendKeys(Keys.ENTER);
+ releaseKey(Keys.SHIFT);
+ assertLog("8. Sort order: [Column 0 ASCENDING, Column 1 DESCENDING, Column 2 ASCENDING] by USER");
+
+ // Move back to the third column
+ sendKeys(Keys.RIGHT);
+
+ // Set sorting to third column, ASCENDING
+ sendKeys(Keys.ENTER);
+ assertLog("10. Sort order: [Column 2 ASCENDING] by USER");
+
+ // Move to the fourth column
+ sendKeys(Keys.RIGHT);
+
+ // Make sure that single-column sorting also works as expected
+ sendKeys(Keys.ENTER);
+ assertLog("12. Sort order: [Column 3 ASCENDING] by USER");
+
+ }
+
+ private void sortBy(String column) {
+ selectMenuPath("Component", "State", "Sort by column", column);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java
new file mode 100644
index 0000000000..21bf667bae
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.basicfeatures.server;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+public class GridStaticSectionComponentTest extends GridBasicFeaturesTest {
+
+ @Test
+ public void testNativeButtonInHeader() throws IOException {
+ openTestURL();
+
+ selectMenuPath("Component", "Columns", "Column 1", "Header Type",
+ "Widget Header");
+
+ getGridElement().$(ButtonElement.class).first().click();
+
+ assertEquals("2. Button clicked!", getLogRow(0));
+ }
+
+ @Test
+ public void testNativeButtonInFooter() throws IOException {
+ openTestURL();
+
+ selectMenuPath("Component", "Footer", "Visible");
+ selectMenuPath("Component", "Footer", "Append row");
+ selectMenuPath("Component", "Columns", "Column 1", "Footer Type",
+ "Widget Footer");
+
+ getGridElement().$(ButtonElement.class).first().click();
+
+ assertEquals("4. Button clicked!", getLogRow(0));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java
new file mode 100644
index 0000000000..a3cbaa980d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java
@@ -0,0 +1,252 @@
+/*
+ * 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.basicfeatures.server;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+public class GridStructureTest extends GridBasicFeaturesTest {
+
+ @Test
+ public void testHidingColumn() throws Exception {
+ openTestURL();
+
+ // Column 0 should be visible
+ List<TestBenchElement> cells = getGridHeaderRowCells();
+ assertEquals("Column 0", cells.get(0).getText());
+
+ // Hide column 0
+ selectMenuPath("Component", "Columns", "Column 0", "Visible");
+
+ // Column 1 should now be the first cell
+ cells = getGridHeaderRowCells();
+ assertEquals("Column 1", cells.get(0).getText());
+ }
+
+ @Test
+ public void testRemovingColumn() throws Exception {
+ openTestURL();
+
+ // Column 0 should be visible
+ List<TestBenchElement> cells = getGridHeaderRowCells();
+ assertEquals("Column 0", cells.get(0).getText());
+
+ // Hide column 0
+ selectMenuPath("Component", "Columns", "Column 0", "Remove");
+
+ // Column 1 should now be the first cell
+ cells = getGridHeaderRowCells();
+ assertEquals("Column 1", cells.get(0).getText());
+ }
+
+ @Test
+ public void testDataLoadingAfterRowRemoval() throws Exception {
+ openTestURL();
+
+ // Remove columns 2,3,4
+ selectMenuPath("Component", "Columns", "Column 2", "Remove");
+ selectMenuPath("Component", "Columns", "Column 3", "Remove");
+ selectMenuPath("Component", "Columns", "Column 4", "Remove");
+
+ // Scroll so new data is lazy loaded
+ scrollGridVerticallyTo(1000);
+
+ // Let lazy loading do its job
+ sleep(1000);
+
+ // Check that row is loaded
+ assertThat(getGridElement().getCell(11, 0).getText(), not("..."));
+ }
+
+ @Test
+ public void testFreezingColumn() throws Exception {
+ openTestURL();
+
+ // Freeze column 2
+ selectMenuPath("Component", "Columns", "Column 2", "Freeze");
+
+ WebElement cell = getGridElement().getCell(0, 0);
+ assertTrue(cell.getAttribute("class").contains("frozen"));
+
+ cell = getGridElement().getCell(0, 1);
+ assertTrue(cell.getAttribute("class").contains("frozen"));
+ }
+
+ @Test
+ public void testInitialColumnWidths() throws Exception {
+ openTestURL();
+
+ WebElement cell = getGridElement().getCell(0, 0);
+ assertEquals(100, cell.getSize().getWidth());
+
+ cell = getGridElement().getCell(0, 1);
+ assertEquals(150, cell.getSize().getWidth());
+
+ cell = getGridElement().getCell(0, 2);
+ assertEquals(200, cell.getSize().getWidth());
+ }
+
+ @Test
+ public void testColumnWidths() throws Exception {
+ openTestURL();
+
+ // Default column width is 100px
+ WebElement cell = getGridElement().getCell(0, 0);
+ assertEquals(100, cell.getSize().getWidth());
+
+ // Set first column to be 200px wide
+ selectMenuPath("Component", "Columns", "Column 0", "Column 0 Width",
+ "200px");
+
+ cell = getGridElement().getCell(0, 0);
+ assertEquals(200, cell.getSize().getWidth());
+
+ // Set second column to be 150px wide
+ selectMenuPath("Component", "Columns", "Column 1", "Column 1 Width",
+ "150px");
+ cell = getGridElement().getCell(0, 1);
+ assertEquals(150, cell.getSize().getWidth());
+
+ // Set first column to be auto sized (defaults to 100px currently)
+ selectMenuPath("Component", "Columns", "Column 0", "Column 0 Width",
+ "Auto");
+
+ cell = getGridElement().getCell(0, 0);
+ assertEquals(100, cell.getSize().getWidth());
+ }
+
+ @Test
+ public void testPrimaryStyleNames() throws Exception {
+ openTestURL();
+
+ // v-grid is default primary style namea
+ assertPrimaryStylename("v-grid");
+
+ selectMenuPath("Component", "State", "Primary style name",
+ "v-escalator");
+ assertPrimaryStylename("v-escalator");
+
+ selectMenuPath("Component", "State", "Primary style name", "my-grid");
+ assertPrimaryStylename("my-grid");
+
+ selectMenuPath("Component", "State", "Primary style name", "v-grid");
+ assertPrimaryStylename("v-grid");
+ }
+
+ /**
+ * Test that the current view is updated when a server-side container change
+ * occurs (without scrolling back and forth)
+ */
+ @Test
+ public void testItemSetChangeEvent() throws Exception {
+ openTestURL();
+
+ final By newRow = By.xpath("//td[text()='newcell: 0']");
+
+ assertTrue("Unexpected initial state", !isElementPresent(newRow));
+
+ selectMenuPath("Component", "Body rows", "Add first row");
+ assertTrue("Add row failed", isElementPresent(newRow));
+
+ selectMenuPath("Component", "Body rows", "Remove first row");
+ assertTrue("Remove row failed", !isElementPresent(newRow));
+ }
+
+ /**
+ * Test that the current view is updated when a property's value is reflect
+ * to the client, when the value is modified server-side.
+ */
+ @Test
+ public void testPropertyValueChangeEvent() throws Exception {
+ openTestURL();
+
+ assertEquals("Unexpected cell initial state", "(0, 0)",
+ getGridElement().getCell(0, 0).getText());
+
+ selectMenuPath("Component", "Body rows",
+ "Modify first row (getItemProperty)");
+ assertEquals("(First) modification with getItemProperty failed",
+ "modified: 0", getGridElement().getCell(0, 0).getText());
+
+ selectMenuPath("Component", "Body rows",
+ "Modify first row (getContainerProperty)");
+ assertEquals("(Second) modification with getItemProperty failed",
+ "modified: Column 0", getGridElement().getCell(0, 0).getText());
+ }
+
+ @Test
+ public void testRemovingAllItems() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Body rows", "Remove all rows");
+
+ assertEquals(0, getGridElement().findElement(By.tagName("tbody"))
+ .findElements(By.tagName("tr")).size());
+ }
+
+ @Test
+ public void testVerticalScrollBarVisibilityWhenEnoughRows()
+ throws Exception {
+ openTestURL();
+
+ assertTrue(verticalScrollbarIsPresent());
+
+ selectMenuPath("Component", "Body rows", "Remove all rows");
+ assertFalse(verticalScrollbarIsPresent());
+
+ selectMenuPath("Component", "Body rows", "Add 18 rows");
+ assertFalse(verticalScrollbarIsPresent());
+
+ selectMenuPath("Component", "Body rows", "Add first row");
+ assertTrue(verticalScrollbarIsPresent());
+ }
+
+ private boolean verticalScrollbarIsPresent() {
+ return "scroll".equals(getGridVerticalScrollbar().getCssValue(
+ "overflow-y"));
+ }
+
+ private void assertPrimaryStylename(String stylename) {
+ assertTrue(getGridElement().getAttribute("class").contains(stylename));
+
+ String tableWrapperStyleName = getGridElement().getTableWrapper()
+ .getAttribute("class");
+ assertTrue(tableWrapperStyleName.contains(stylename + "-tablewrapper"));
+
+ String hscrollStyleName = getGridElement().getHorizontalScroller()
+ .getAttribute("class");
+ assertTrue(hscrollStyleName.contains(stylename + "-scroller"));
+ assertTrue(hscrollStyleName
+ .contains(stylename + "-scroller-horizontal"));
+
+ String vscrollStyleName = getGridElement().getVerticalScroller()
+ .getAttribute("class");
+ assertTrue(vscrollStyleName.contains(stylename + "-scroller"));
+ assertTrue(vscrollStyleName.contains(stylename + "-scroller-vertical"));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
index 2c25c54e04..d23903f9db 100644
--- a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
+++ b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
@@ -4,6 +4,8 @@
<!-- Inherit the DefaultWidgetSet -->
<inherits name="com.vaadin.DefaultWidgetSet" />
+ <inherits name="com.google.gwt.user.theme.standard.Standard" />
+
<replace-with class="com.vaadin.tests.widgetset.client.CustomUIConnector">
<when-type-is class="com.vaadin.client.ui.ui.UIConnector" />
</replace-with>
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesConnector.java
new file mode 100644
index 0000000000..f065d4c7f6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesConnector.java
@@ -0,0 +1,37 @@
+/*
+ * 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.client.ui.AbstractComponentConnector;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.tests.components.grid.basicfeatures.EscalatorBasicClientFeatures.EscalatorTestComponent;
+
+/**
+ * Connector for the EscalatorClientBasicFeatures ApplicationWidget
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+@Connect(EscalatorTestComponent.class)
+public class EscalatorBasicClientFeaturesConnector extends
+ AbstractComponentConnector {
+
+ @Override
+ public EscalatorBasicClientFeaturesWidget getWidget() {
+ return (EscalatorBasicClientFeaturesWidget) super.getWidget();
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java
new file mode 100644
index 0000000000..54c870b8f7
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java
@@ -0,0 +1,608 @@
+package com.vaadin.tests.widgetset.client.grid;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.Duration;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.dom.client.TableCellElement;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.client.ui.grid.Escalator;
+import com.vaadin.client.ui.grid.EscalatorUpdater;
+import com.vaadin.client.ui.grid.FlyweightCell;
+import com.vaadin.client.ui.grid.Row;
+import com.vaadin.client.ui.grid.RowContainer;
+
+public class EscalatorBasicClientFeaturesWidget extends
+ PureGWTTestApplication<Escalator> {
+
+ public static class LogWidget extends Composite {
+
+ private static final int MAX_LOG = 9;
+
+ private final HTML html = new HTML();
+ private final List<String> logs = new ArrayList<String>();
+ private Escalator escalator;
+
+ public LogWidget() {
+ initWidget(html);
+ getElement().setId("log");
+ }
+
+ public void setEscalator(Escalator escalator) {
+ this.escalator = escalator;
+ }
+
+ public void updateDebugLabel() {
+ int headers = escalator.getHeader().getRowCount();
+ int bodys = escalator.getBody().getRowCount();
+ int footers = escalator.getFooter().getRowCount();
+ int columns = escalator.getColumnConfiguration().getColumnCount();
+
+ while (logs.size() > MAX_LOG) {
+ logs.remove(0);
+ }
+
+ String logString = "<hr>";
+ for (String log : logs) {
+ logString += log + "<br>";
+ }
+
+ html.setHTML("Columns: " + columns + "<br>" + //
+ "Header rows: " + headers + "<br>" + //
+ "Body rows: " + bodys + "<br>" + //
+ "Footer rows: " + footers + "<br>" + //
+ logString);
+ }
+
+ public void log(String string) {
+ logs.add((Duration.currentTimeMillis() % 10000) + ": " + string);
+ }
+ }
+
+ public static class UpdaterLifetimeWidget extends
+ EscalatorBasicClientFeaturesWidget {
+
+ private final EscalatorUpdater debugUpdater = new EscalatorUpdater() {
+ @Override
+ public void preAttach(Row row, Iterable<FlyweightCell> cellsToAttach) {
+ log("preAttach", cellsToAttach);
+ }
+
+ @Override
+ public void postAttach(Row row,
+ Iterable<FlyweightCell> attachedCells) {
+ log("postAttach", attachedCells);
+ }
+
+ @Override
+ public void update(Row row, Iterable<FlyweightCell> cellsToUpdate) {
+ log("update", cellsToUpdate);
+ }
+
+ @Override
+ public void preDetach(Row row, Iterable<FlyweightCell> cellsToDetach) {
+ log("preDetach", cellsToDetach);
+ }
+
+ @Override
+ public void postDetach(Row row,
+ Iterable<FlyweightCell> detachedCells) {
+ log("postDetach", detachedCells);
+ }
+
+ private void log(String methodName, Iterable<FlyweightCell> cells) {
+ if (!cells.iterator().hasNext()) {
+ return;
+ }
+
+ TableCellElement cellElement = cells.iterator().next()
+ .getElement();
+ boolean isAttached = cellElement.getParentElement() != null
+ && cellElement.getParentElement().getParentElement() != null;
+ logWidget.log(methodName + ": elementIsAttached == "
+ + isAttached);
+ }
+ };
+
+ public UpdaterLifetimeWidget() {
+ super();
+ escalator.getHeader().setEscalatorUpdater(debugUpdater);
+ escalator.getBody().setEscalatorUpdater(debugUpdater);
+ escalator.getFooter().setEscalatorUpdater(debugUpdater);
+ }
+ }
+
+ private static final String COLUMNS_AND_ROWS_MENU = "Columns and Rows";
+ private static final String GENERAL_MENU = "General";
+ private static final String FEATURES_MENU = "Features";
+
+ private static abstract class TestEscalatorUpdater implements
+ EscalatorUpdater {
+
+ @Override
+ public void preAttach(Row row, Iterable<FlyweightCell> cellsToAttach) {
+ // noop
+ }
+
+ @Override
+ public void postAttach(Row row, Iterable<FlyweightCell> attachedCells) {
+ // noop
+ }
+
+ @Override
+ public void preDetach(Row row, Iterable<FlyweightCell> cellsToDetach) {
+ // noop
+ }
+
+ @Override
+ public void postDetach(Row row, Iterable<FlyweightCell> detachedCells) {
+ // noop
+ }
+ }
+
+ private class Data {
+ private int columnCounter = 0;
+ private int rowCounter = 0;
+ private final List<Integer> columns = new ArrayList<Integer>();
+ private final List<Integer> rows = new ArrayList<Integer>();
+
+ @SuppressWarnings("boxing")
+ public void insertRows(final int offset, final int amount) {
+ final List<Integer> newRows = new ArrayList<Integer>();
+ for (int i = 0; i < amount; i++) {
+ newRows.add(rowCounter++);
+ }
+ rows.addAll(offset, newRows);
+ }
+
+ @SuppressWarnings("boxing")
+ public void insertColumns(final int offset, final int amount) {
+ final List<Integer> newColumns = new ArrayList<Integer>();
+ for (int i = 0; i < amount; i++) {
+ newColumns.add(columnCounter++);
+ }
+ columns.addAll(offset, newColumns);
+ }
+
+ public EscalatorUpdater createHeaderUpdater() {
+ return new TestEscalatorUpdater() {
+ @Override
+ public void update(final Row row,
+ final Iterable<FlyweightCell> cellsToUpdate) {
+ for (final FlyweightCell cell : cellsToUpdate) {
+ final Integer columnName = columns
+ .get(cell.getColumn());
+ cell.getElement().setInnerText("Header " + columnName);
+
+ if (colspan == Colspan.NORMAL) {
+ if (cell.getColumn() % 2 == 0) {
+ cell.setColSpan(2);
+ }
+ } else if (colspan == Colspan.CRAZY) {
+ if (cell.getColumn() % 3 == 0) {
+ cell.setColSpan(2);
+ }
+ }
+ }
+ }
+ };
+ }
+
+ public EscalatorUpdater createFooterUpdater() {
+ return new TestEscalatorUpdater() {
+ @Override
+ public void update(final Row row,
+ final Iterable<FlyweightCell> cellsToUpdate) {
+ for (final FlyweightCell cell : cellsToUpdate) {
+ final Integer columnName = columns
+ .get(cell.getColumn());
+ cell.getElement().setInnerText("Footer " + columnName);
+
+ if (colspan == Colspan.NORMAL) {
+ if (cell.getColumn() % 2 == 0) {
+ cell.setColSpan(2);
+ }
+ } else if (colspan == Colspan.CRAZY) {
+ if (cell.getColumn() % 3 == 1) {
+ cell.setColSpan(2);
+ }
+ }
+ }
+ }
+ };
+ }
+
+ public EscalatorUpdater createBodyUpdater() {
+ return new TestEscalatorUpdater() {
+
+ public void renderCell(final FlyweightCell cell) {
+ final Integer columnName = columns.get(cell.getColumn());
+ final Integer rowName = rows.get(cell.getRow());
+ String cellInfo = columnName + "," + rowName;
+
+ if (cell.getColumn() > 0) {
+ cell.getElement().setInnerText("Cell: " + cellInfo);
+ } else {
+ cell.getElement().setInnerText(
+ "Row " + cell.getRow() + ": " + cellInfo);
+ }
+
+ if (colspan == Colspan.NORMAL) {
+ if (cell.getColumn() % 2 == 0) {
+ cell.setColSpan(2);
+ }
+ } else if (colspan == Colspan.CRAZY) {
+ if (cell.getColumn() % 3 == cell.getRow() % 3) {
+ cell.setColSpan(2);
+ }
+ }
+ }
+
+ @Override
+ public void update(final Row row,
+ final Iterable<FlyweightCell> cellsToUpdate) {
+ for (final FlyweightCell cell : cellsToUpdate) {
+ renderCell(cell);
+ }
+ }
+ };
+ }
+
+ public void removeRows(final int offset, final int amount) {
+ for (int i = 0; i < amount; i++) {
+ rows.remove(offset);
+ }
+ }
+
+ public void removeColumns(final int offset, final int amount) {
+ for (int i = 0; i < amount; i++) {
+ columns.remove(offset);
+ }
+ }
+ }
+
+ protected final Escalator escalator;
+ private final Data data = new Data();
+
+ private enum Colspan {
+ NONE, NORMAL, CRAZY;
+ }
+
+ private Colspan colspan = Colspan.NONE;
+ protected final LogWidget logWidget = new LogWidget();
+
+ public EscalatorBasicClientFeaturesWidget() {
+ super(new EscalatorProxy());
+ escalator = getTestedWidget();
+ logWidget.setEscalator(escalator);
+
+ ((EscalatorProxy) escalator).setLogWidget(logWidget);
+ addNorth(logWidget, 200);
+
+ final RowContainer header = escalator.getHeader();
+ header.setEscalatorUpdater(data.createHeaderUpdater());
+
+ final RowContainer footer = escalator.getFooter();
+ footer.setEscalatorUpdater(data.createFooterUpdater());
+
+ escalator.getBody().setEscalatorUpdater(data.createBodyUpdater());
+
+ setWidth("500px");
+ setHeight("500px");
+
+ escalator.getElement().getStyle().setZIndex(0);
+ addNorth(escalator, 500);
+
+ createGeneralMenu();
+ createColumnMenu();
+ createHeaderRowsMenu();
+ createBodyRowsMenu();
+ createFooterRowsMenu();
+ createColumnsAndRowsMenu();
+ createFrozenMenu();
+ createColspanMenu();
+ }
+
+ private void createFrozenMenu() {
+ String[] menupath = { FEATURES_MENU, "Frozen columns" };
+ addMenuCommand("Freeze 1 column", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ escalator.getColumnConfiguration().setFrozenColumnCount(1);
+ }
+ }, menupath);
+ addMenuCommand("Freeze 0 columns", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ escalator.getColumnConfiguration().setFrozenColumnCount(0);
+ }
+ }, menupath);
+ }
+
+ private void createColspanMenu() {
+ String[] menupath = { FEATURES_MENU, "Column spanning" };
+ addMenuCommand("Apply normal colspan", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ colspan = Colspan.NORMAL;
+ refreshEscalator();
+ }
+ }, menupath);
+ addMenuCommand("Apply crazy colspan", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ colspan = Colspan.CRAZY;
+ refreshEscalator();
+ }
+ }, menupath);
+ addMenuCommand("Apply no colspan", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ colspan = Colspan.NONE;
+ refreshEscalator();
+ }
+ }, menupath);
+ }
+
+ private void createColumnsAndRowsMenu() {
+ String[] menupath = { COLUMNS_AND_ROWS_MENU };
+ addMenuCommand("Add one of each row", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ insertRows(escalator.getHeader(), 0, 1);
+ insertRows(escalator.getBody(), 0, 1);
+ insertRows(escalator.getFooter(), 0, 1);
+ }
+ }, menupath);
+ addMenuCommand("Remove one of each row", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ removeRows(escalator.getHeader(), 0, 1);
+ removeRows(escalator.getBody(), 0, 1);
+ removeRows(escalator.getFooter(), 0, 1);
+ }
+ }, menupath);
+ }
+
+ private void createGeneralMenu() {
+ String[] menupath = { GENERAL_MENU };
+ addMenuCommand("Clear (columns, then rows)", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ resetColRow();
+ }
+ }, menupath);
+ addMenuCommand("Clear (rows, then columns)", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ resetRowCol();
+ }
+ }, menupath);
+ addMenuCommand("Populate Escalator (columns, then rows)",
+ new ScheduledCommand() {
+ @Override
+ public void execute() {
+ resetColRow();
+ insertColumns(0, 10);
+ insertRows(escalator.getHeader(), 0, 1);
+ insertRows(escalator.getBody(), 0, 100);
+ insertRows(escalator.getFooter(), 0, 1);
+ }
+ }, menupath);
+ addMenuCommand("Populate Escalator (rows, then columns)",
+ new ScheduledCommand() {
+ @Override
+ public void execute() {
+ resetColRow();
+ insertRows(escalator.getHeader(), 0, 1);
+ insertRows(escalator.getBody(), 0, 100);
+ insertRows(escalator.getFooter(), 0, 1);
+ insertColumns(0, 10);
+ }
+ }, menupath);
+ }
+
+ private void createColumnMenu() {
+ String[] menupath = { COLUMNS_AND_ROWS_MENU, "Columns" };
+ addMenuCommand("Add one column to beginning", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ insertColumns(0, 1);
+ }
+ }, menupath);
+ addMenuCommand("Add one column to end", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ insertColumns(escalator.getColumnConfiguration()
+ .getColumnCount(), 1);
+ }
+ }, menupath);
+ addMenuCommand("Add ten columns", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ insertColumns(0, 10);
+ }
+ }, menupath);
+ addMenuCommand("Remove one column from beginning",
+ new ScheduledCommand() {
+ @Override
+ public void execute() {
+ removeColumns(0, 1);
+ }
+ }, menupath);
+ addMenuCommand("Remove one column from end", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ removeColumns(escalator.getColumnConfiguration()
+ .getColumnCount() - 1, 1);
+ }
+ }, menupath);
+ }
+
+ private void createHeaderRowsMenu() {
+ String[] menupath = { COLUMNS_AND_ROWS_MENU, "Header Rows" };
+ createRowsMenu(escalator.getHeader(), menupath);
+ }
+
+ private void createFooterRowsMenu() {
+ String[] menupath = { COLUMNS_AND_ROWS_MENU, "Footer Rows" };
+ createRowsMenu(escalator.getFooter(), menupath);
+ }
+
+ private void createBodyRowsMenu() {
+ String[] menupath = { COLUMNS_AND_ROWS_MENU, "Body Rows" };
+ createRowsMenu(escalator.getBody(), menupath);
+
+ addMenuCommand("Add 5 rows to top", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ insertRows(escalator.getBody(), 0, 5);
+ }
+ }, menupath);
+ addMenuCommand("Add 50 rows to top", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ insertRows(escalator.getBody(), 0, 50);
+ }
+ }, menupath);
+ addMenuCommand("Remove 5 rows from bottom", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ removeRows(escalator.getBody(), escalator.getBody()
+ .getRowCount() - 5, 5);
+ }
+ }, menupath);
+ addMenuCommand("Remove 50 rows from bottom", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ removeRows(escalator.getBody(), escalator.getBody()
+ .getRowCount() - 50, 50);
+ }
+ }, menupath);
+ }
+
+ private void createRowsMenu(final RowContainer container, String[] menupath) {
+ addMenuCommand("Add one row to beginning", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ int offset = 0;
+ int number = 1;
+ insertRows(container, offset, number);
+ }
+ }, menupath);
+ addMenuCommand("Add one row to end", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ int offset = container.getRowCount();
+ int number = 1;
+ insertRows(container, offset, number);
+ }
+ }, menupath);
+ addMenuCommand("Remove one row from beginning", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ int offset = 0;
+ int number = 1;
+ removeRows(container, offset, number);
+ }
+ }, menupath);
+ addMenuCommand("Remove one row from end", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ int offset = container.getRowCount() - 1;
+ int number = 1;
+ removeRows(container, offset, number);
+ }
+ }, menupath);
+ }
+
+ private void insertRows(final RowContainer container, int offset, int number) {
+ if (container == escalator.getBody()) {
+ data.insertRows(offset, number);
+ escalator.getBody().insertRows(offset, number);
+ } else {
+ container.insertRows(offset, number);
+ }
+ }
+
+ private void removeRows(final RowContainer container, int offset, int number) {
+ if (container == escalator.getBody()) {
+ data.removeRows(offset, number);
+ escalator.getBody().removeRows(offset, number);
+ } else {
+ container.removeRows(offset, number);
+ }
+ }
+
+ private void insertColumns(final int offset, final int number) {
+ data.insertColumns(offset, number);
+ escalator.getColumnConfiguration().insertColumns(offset, number);
+ }
+
+ private void removeColumns(final int offset, final int number) {
+ data.removeColumns(offset, number);
+ escalator.getColumnConfiguration().removeColumns(offset, number);
+ }
+
+ private void resetColRow() {
+ if (escalator.getColumnConfiguration().getColumnCount() > 0) {
+ removeColumns(0, escalator.getColumnConfiguration()
+ .getColumnCount());
+ }
+ if (escalator.getFooter().getRowCount() > 0) {
+ removeRows(escalator.getFooter(), 0, escalator.getFooter()
+ .getRowCount());
+ }
+
+ if (escalator.getBody().getRowCount() > 0) {
+ removeRows(escalator.getBody(), 0, escalator.getBody()
+ .getRowCount());
+ }
+
+ if (escalator.getHeader().getRowCount() > 0) {
+ removeRows(escalator.getHeader(), 0, escalator.getHeader()
+ .getRowCount());
+ }
+ }
+
+ private void resetRowCol() {
+ if (escalator.getFooter().getRowCount() > 0) {
+ removeRows(escalator.getFooter(), 0, escalator.getFooter()
+ .getRowCount());
+ }
+
+ if (escalator.getBody().getRowCount() > 0) {
+ removeRows(escalator.getBody(), 0, escalator.getBody()
+ .getRowCount());
+ }
+
+ if (escalator.getHeader().getRowCount() > 0) {
+ removeRows(escalator.getHeader(), 0, escalator.getHeader()
+ .getRowCount());
+ }
+
+ if (escalator.getColumnConfiguration().getColumnCount() > 0) {
+ removeColumns(0, escalator.getColumnConfiguration()
+ .getColumnCount());
+ }
+ }
+
+ private void refreshEscalator() {
+ if (escalator.getHeader().getRowCount() > 0) {
+ escalator.getHeader().refreshRows(0,
+ escalator.getHeader().getRowCount());
+ }
+
+ if (escalator.getBody().getRowCount() > 0) {
+ escalator.getBody().refreshRows(0,
+ escalator.getBody().getRowCount());
+ }
+
+ if (escalator.getFooter().getRowCount() > 0) {
+ escalator.getFooter().refreshRows(0,
+ escalator.getFooter().getRowCount());
+ }
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java
new file mode 100644
index 0000000000..ac1de01f1e
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java
@@ -0,0 +1,206 @@
+/*
+ * 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.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.TableRowElement;
+import com.vaadin.client.ui.grid.Cell;
+import com.vaadin.client.ui.grid.ColumnConfiguration;
+import com.vaadin.client.ui.grid.Escalator;
+import com.vaadin.client.ui.grid.EscalatorUpdater;
+import com.vaadin.client.ui.grid.RowContainer;
+import com.vaadin.tests.widgetset.client.grid.EscalatorBasicClientFeaturesWidget.LogWidget;
+
+public class EscalatorProxy extends Escalator {
+ private class ColumnConfigurationProxy implements ColumnConfiguration {
+ private ColumnConfiguration columnConfiguration;
+
+ public ColumnConfigurationProxy(ColumnConfiguration columnConfiguration) {
+ this.columnConfiguration = columnConfiguration;
+ }
+
+ @Override
+ public void removeColumns(int index, int numberOfColumns)
+ throws IndexOutOfBoundsException, IllegalArgumentException {
+ columnConfiguration.removeColumns(index, numberOfColumns);
+ logWidget.log("removeColumns " + index + ", " + numberOfColumns);
+ logWidget.updateDebugLabel();
+ }
+
+ @Override
+ public void insertColumns(int index, int numberOfColumns)
+ throws IndexOutOfBoundsException, IllegalArgumentException {
+ columnConfiguration.insertColumns(index, numberOfColumns);
+ logWidget.log("insertColumns " + index + ", " + numberOfColumns);
+ logWidget.updateDebugLabel();
+ }
+
+ @Override
+ public int getColumnCount() {
+ return columnConfiguration.getColumnCount();
+ }
+
+ @Override
+ public void setFrozenColumnCount(int count)
+ throws IllegalArgumentException {
+ columnConfiguration.setFrozenColumnCount(count);
+ }
+
+ @Override
+ public int getFrozenColumnCount() {
+ return columnConfiguration.getFrozenColumnCount();
+ }
+
+ @Override
+ public void setColumnWidth(int index, int px)
+ throws IllegalArgumentException {
+ columnConfiguration.setColumnWidth(index, px);
+ }
+
+ @Override
+ public int getColumnWidth(int index) throws IllegalArgumentException {
+ return columnConfiguration.getColumnWidth(index);
+ }
+
+ @Override
+ public int getColumnWidthActual(int index)
+ throws IllegalArgumentException {
+ return columnConfiguration.getColumnWidthActual(index);
+ }
+ }
+
+ private class RowContainerProxy implements RowContainer {
+ private final RowContainer rowContainer;
+
+ public RowContainerProxy(RowContainer rowContainer) {
+ this.rowContainer = rowContainer;
+ }
+
+ @Override
+ public EscalatorUpdater getEscalatorUpdater() {
+ return rowContainer.getEscalatorUpdater();
+ }
+
+ @Override
+ public void setEscalatorUpdater(EscalatorUpdater escalatorUpdater)
+ throws IllegalArgumentException {
+ rowContainer.setEscalatorUpdater(escalatorUpdater);
+ }
+
+ @Override
+ public void removeRows(int index, int numberOfRows)
+ throws IndexOutOfBoundsException, IllegalArgumentException {
+ rowContainer.removeRows(index, numberOfRows);
+ logWidget.log(rowContainer.getClass().getSimpleName()
+ + " removeRows " + index + ", " + numberOfRows);
+ logWidget.updateDebugLabel();
+ }
+
+ @Override
+ public void insertRows(int index, int numberOfRows)
+ throws IndexOutOfBoundsException, IllegalArgumentException {
+ rowContainer.insertRows(index, numberOfRows);
+ logWidget.log(rowContainer.getClass().getSimpleName()
+ + " insertRows " + index + ", " + numberOfRows);
+ logWidget.updateDebugLabel();
+ }
+
+ @Override
+ public void refreshRows(int index, int numberOfRows)
+ throws IndexOutOfBoundsException, IllegalArgumentException {
+ rowContainer.refreshRows(index, numberOfRows);
+ logWidget.log(rowContainer.getClass().getSimpleName()
+ + " refreshRows " + index + ", " + numberOfRows);
+ }
+
+ @Override
+ public int getRowCount() {
+ return rowContainer.getRowCount();
+ }
+
+ @Override
+ public void setDefaultRowHeight(int px) throws IllegalArgumentException {
+ rowContainer.setDefaultRowHeight(px);
+ }
+
+ @Override
+ public int getDefaultRowHeight() {
+ return rowContainer.getDefaultRowHeight();
+ }
+
+ @Override
+ public Cell getCell(Element element) {
+ return rowContainer.getCell(element);
+ }
+
+ @Override
+ public TableRowElement getRowElement(int index)
+ throws IndexOutOfBoundsException, IllegalStateException {
+ return rowContainer.getRowElement(index);
+ }
+
+ @Override
+ public Element getElement() {
+ return rowContainer.getElement();
+ }
+
+ }
+
+ private RowContainer headerProxy = null;
+ private RowContainer bodyProxy = null;
+ private RowContainer footerProxy = null;
+ private ColumnConfiguration columnProxy = null;
+ private LogWidget logWidget;
+
+ @Override
+ public RowContainer getHeader() {
+ if (headerProxy == null) {
+ headerProxy = new RowContainerProxy(super.getHeader());
+ }
+ return headerProxy;
+ }
+
+ @Override
+ public RowContainer getFooter() {
+ if (footerProxy == null) {
+ footerProxy = new RowContainerProxy(super.getFooter());
+ }
+ return footerProxy;
+ }
+
+ @Override
+ public RowContainer getBody() {
+ if (bodyProxy == null) {
+ bodyProxy = new RowContainerProxy(super.getBody());
+ }
+ return bodyProxy;
+ }
+
+ @Override
+ public ColumnConfiguration getColumnConfiguration() {
+ if (columnProxy == null) {
+ columnProxy = new ColumnConfigurationProxy(
+ super.getColumnConfiguration());
+ }
+ return columnProxy;
+ }
+
+ public void setLogWidget(LogWidget logWidget) {
+ this.logWidget = logWidget;
+ logWidget.updateDebugLabel();
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorUpdaterTestConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorUpdaterTestConnector.java
new file mode 100644
index 0000000000..4ef8972e4f
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorUpdaterTestConnector.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.tests.widgetset.client.grid;
+
+import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.tests.components.grid.basicfeatures.EscalatorUpdaterUi.EscalatorUpdaterTestComponent;
+
+@Connect(EscalatorUpdaterTestComponent.class)
+public class EscalatorUpdaterTestConnector extends AbstractComponentConnector {
+
+ @Override
+ public EscalatorBasicClientFeaturesWidget.UpdaterLifetimeWidget getWidget() {
+ return (EscalatorBasicClientFeaturesWidget.UpdaterLifetimeWidget) super
+ .getWidget();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesConnector.java
new file mode 100644
index 0000000000..b0841b69fb
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesConnector.java
@@ -0,0 +1,37 @@
+/*
+ * 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.client.ui.AbstractComponentConnector;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeatures.GridTestComponent;
+
+/**
+ * Connector for the GridClientBasicFeatures ApplicationWidget
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+@Connect(GridTestComponent.class)
+public class GridBasicClientFeaturesConnector extends
+ AbstractComponentConnector {
+
+ @Override
+ public GridBasicClientFeaturesWidget getWidget() {
+ return (GridBasicClientFeaturesWidget) super.getWidget();
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java
new file mode 100644
index 0000000000..d5d276c7db
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java
@@ -0,0 +1,931 @@
+/*
+ * 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.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.TextBox;
+import com.vaadin.client.ui.VLabel;
+import com.vaadin.client.ui.grid.Cell;
+import com.vaadin.client.ui.grid.EditorRowHandler;
+import com.vaadin.client.ui.grid.FlyweightCell;
+import com.vaadin.client.ui.grid.Grid;
+import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent;
+import com.vaadin.client.ui.grid.Grid.SelectionMode;
+import com.vaadin.client.ui.grid.GridColumn;
+import com.vaadin.client.ui.grid.GridFooter;
+import com.vaadin.client.ui.grid.GridFooter.FooterRow;
+import com.vaadin.client.ui.grid.GridHeader;
+import com.vaadin.client.ui.grid.GridHeader.HeaderRow;
+import com.vaadin.client.ui.grid.Renderer;
+import com.vaadin.client.ui.grid.datasources.ListDataSource;
+import com.vaadin.client.ui.grid.datasources.ListSorter;
+import com.vaadin.client.ui.grid.events.BodyKeyDownHandler;
+import com.vaadin.client.ui.grid.events.BodyKeyPressHandler;
+import com.vaadin.client.ui.grid.events.BodyKeyUpHandler;
+import com.vaadin.client.ui.grid.events.FooterKeyDownHandler;
+import com.vaadin.client.ui.grid.events.FooterKeyPressHandler;
+import com.vaadin.client.ui.grid.events.FooterKeyUpHandler;
+import com.vaadin.client.ui.grid.events.GridKeyDownEvent;
+import com.vaadin.client.ui.grid.events.GridKeyPressEvent;
+import com.vaadin.client.ui.grid.events.GridKeyUpEvent;
+import com.vaadin.client.ui.grid.events.HeaderKeyDownHandler;
+import com.vaadin.client.ui.grid.events.HeaderKeyPressHandler;
+import com.vaadin.client.ui.grid.events.HeaderKeyUpHandler;
+import com.vaadin.client.ui.grid.events.ScrollEvent;
+import com.vaadin.client.ui.grid.events.ScrollHandler;
+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.selection.SelectionModel.None;
+import com.vaadin.tests.widgetset.client.grid.GridBasicClientFeaturesWidget.Data;
+
+/**
+ * Grid basic client features test application.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class GridBasicClientFeaturesWidget extends
+ PureGWTTestApplication<Grid<List<Data>>> {
+
+ public static enum Renderers {
+ TEXT_RENDERER, HTML_RENDERER, NUMBER_RENDERER, DATE_RENDERER;
+ }
+
+ private class TestEditorRowHandler implements EditorRowHandler<List<Data>> {
+
+ private Map<GridColumn<?, ?>, TextBox> widgets = new HashMap<GridColumn<?, ?>, TextBox>();
+
+ private Label log = new Label();
+
+ {
+ log.addStyleName("editor-row-log");
+ addSouth(log, 20);
+ }
+
+ @Override
+ public void bind(EditorRowRequest request) {
+ List<Data> rowData = ds.getRow(request.getRowIndex());
+
+ boolean hasSelectionColumn = !(grid.getSelectionModel() instanceof None);
+ for (int i = 0; i < rowData.size(); i++) {
+ int columnIndex = hasSelectionColumn ? i + 1 : i;
+ getWidget(columnIndex).setText(rowData.get(i).value.toString());
+ }
+
+ request.invokeCallback();
+ }
+
+ @Override
+ public void cancel(EditorRowRequest request) {
+ log.setText("Row " + request.getRowIndex() + " edit cancelled");
+ request.invokeCallback();
+ }
+
+ @Override
+ public void commit(EditorRowRequest request) {
+ log.setText("Row " + request.getRowIndex() + " edit committed");
+ List<Data> rowData = ds.getRow(request.getRowIndex());
+
+ int i = 0;
+ for (; i < COLUMNS - MANUALLY_FORMATTED_COLUMNS; i++) {
+ rowData.get(i).value = getWidget(i).getText();
+ }
+
+ rowData.get(i).value = Integer.valueOf(getWidget(i++).getText());
+ rowData.get(i).value = new Date(getWidget(i++).getText());
+ rowData.get(i).value = getWidget(i++).getText();
+ rowData.get(i).value = Integer.valueOf(getWidget(i++).getText());
+ rowData.get(i).value = Integer.valueOf(getWidget(i++).getText());
+
+ // notify data source of changes
+ ds.asList().set(request.getRowIndex(), rowData);
+
+ request.invokeCallback();
+ }
+
+ @Override
+ public void discard(EditorRowRequest request) {
+ bind(request);
+ }
+
+ @Override
+ public TextBox getWidget(GridColumn<?, List<Data>> column) {
+ if (grid.getColumns().indexOf(column) == 0
+ && !(grid.getSelectionModel() instanceof None)) {
+ return null;
+ }
+
+ TextBox w = widgets.get(column);
+ if (w == null) {
+ w = new TextBox();
+ w.getElement().getStyle().setMargin(0, Unit.PX);
+ widgets.put(column, w);
+ }
+ return w;
+ }
+
+ private TextBox getWidget(int i) {
+ return getWidget(grid.getColumn(i));
+ }
+ }
+
+ private static final int MANUALLY_FORMATTED_COLUMNS = 5;
+ public static final int COLUMNS = 12;
+ public static final int ROWS = 1000;
+
+ private final Grid<List<Data>> grid;
+ private final List<List<Data>> data;
+ private final ListDataSource<List<Data>> ds;
+ private final ListSorter<List<Data>> sorter;
+
+ /**
+ * Our basic data object
+ */
+ public final static class Data {
+ Object value;
+ }
+
+ /**
+ * Convenience method for creating a list of Data objects to be used as a
+ * Row in the data source
+ *
+ * @param cols
+ * number of columns (items) to include in the row
+ * @return
+ */
+ private List<Data> createDataRow(int cols) {
+ List<Data> list = new ArrayList<Data>(cols);
+ for (int i = 0; i < cols; ++i) {
+ list.add(new Data());
+ }
+ data.add(list);
+ return list;
+ }
+
+ @SuppressWarnings("unchecked")
+ public GridBasicClientFeaturesWidget() {
+ super(new Grid<List<Data>>());
+
+ // Initialize data source
+ data = new ArrayList<List<Data>>();
+ {
+ Random rand = new Random();
+ rand.setSeed(13334);
+ long timestamp = 0;
+ for (int row = 0; row < ROWS; row++) {
+
+ List<Data> datarow = createDataRow(COLUMNS);
+ Data d;
+
+ int col = 0;
+ for (; col < COLUMNS - MANUALLY_FORMATTED_COLUMNS; ++col) {
+ d = datarow.get(col);
+ d.value = "(" + row + ", " + col + ")";
+ }
+
+ d = datarow.get(col++);
+ d.value = Integer.valueOf(row);
+
+ d = datarow.get(col++);
+ d.value = new Date(timestamp);
+ timestamp += 91250000; // a bit over a day, just to get
+ // variation
+
+ d = datarow.get(col++);
+ d.value = "<b>" + row + "</b>";
+
+ d = datarow.get(col++);
+ d.value = Integer.valueOf(rand.nextInt());
+
+ d = datarow.get(col++);
+ d.value = Integer.valueOf(rand.nextInt(5));
+ }
+ }
+
+ ds = new ListDataSource<List<Data>>(data);
+ grid = getTestedWidget();
+ grid.getElement().setId("testComponent");
+ grid.setDataSource(ds);
+ grid.setSelectionMode(SelectionMode.NONE);
+ grid.getEditorRow().setHandler(new TestEditorRowHandler());
+
+ sorter = new ListSorter<List<Data>>(grid);
+
+ // Create a bunch of grid columns
+
+ // Data source layout:
+ // text (String) * (COLUMNS - MANUALLY_FORMATTED_COLUMNS + 1) |
+ // rownumber (Integer) | some date (Date) | row number as HTML (String)
+ // | random value (Integer)
+
+ int col = 0;
+
+ // Text times COLUMNS - MANUALLY_FORMATTED_COLUMNS
+ for (col = 0; col < COLUMNS - MANUALLY_FORMATTED_COLUMNS; ++col) {
+
+ final int c = col;
+
+ GridColumn<String, List<Data>> column = new GridColumn<String, List<Data>>(
+ createRenderer(Renderers.TEXT_RENDERER)) {
+ @Override
+ public String getValue(List<Data> row) {
+ return (String) row.get(c).value;
+ }
+ };
+
+ column.setWidth(50 + c * 25);
+
+ grid.addColumn(column);
+
+ }
+
+ // Integer row number
+ {
+ final int c = col++;
+ grid.addColumn(new GridColumn<Integer, List<Data>>(
+ createRenderer(Renderers.NUMBER_RENDERER)) {
+ @Override
+ public Integer getValue(List<Data> row) {
+ return (Integer) row.get(c).value;
+ }
+ });
+ }
+
+ // Some date
+ {
+ final int c = col++;
+ grid.addColumn(new GridColumn<Date, List<Data>>(
+ createRenderer(Renderers.DATE_RENDERER)) {
+ @Override
+ public Date getValue(List<Data> row) {
+ return (Date) row.get(c).value;
+ }
+ });
+ }
+
+ // Row number as a HTML string
+ {
+ final int c = col++;
+ grid.addColumn(new GridColumn<String, List<Data>>(
+ createRenderer(Renderers.HTML_RENDERER)) {
+ @Override
+ public String getValue(List<Data> row) {
+ return (String) row.get(c).value;
+ }
+ });
+ }
+
+ // Random integer value
+ {
+ final int c = col++;
+ grid.addColumn(new GridColumn<Integer, List<Data>>(
+ createRenderer(Renderers.NUMBER_RENDERER)) {
+ @Override
+ public Integer getValue(List<Data> row) {
+ return (Integer) row.get(c).value;
+ }
+ });
+ }
+
+ // Random integer value between 0 and 5
+ {
+ final int c = col++;
+ grid.addColumn(new GridColumn<Integer, List<Data>>(
+ createRenderer(Renderers.NUMBER_RENDERER)) {
+ @Override
+ public Integer getValue(List<Data> row) {
+ return (Integer) row.get(c).value;
+ }
+ });
+ }
+
+ setHeaderTexts(grid.getHeader().getRow(0));
+
+ //
+ // Populate the menu
+ //
+
+ createStateMenu();
+ createColumnsMenu();
+ createHeaderMenu();
+ createFooterMenu();
+ createEditorRowMenu();
+ createInternalsMenu();
+
+ grid.getElement().getStyle().setZIndex(0);
+ addNorth(grid, 400);
+
+ createKeyHandlers();
+ }
+
+ private void createInternalsMenu() {
+ String[] listenersPath = { "Component", "Internals", "Listeners" };
+ final Label label = new Label();
+ addSouth(label, 20);
+
+ addMenuCommand("Add scroll listener", new ScheduledCommand() {
+ private HandlerRegistration scrollHandler = null;
+
+ @Override
+ public void execute() {
+ if (scrollHandler != null) {
+ return;
+ }
+ scrollHandler = grid.addScrollHandler(new ScrollHandler() {
+ @Override
+ public void onScroll(ScrollEvent event) {
+ @SuppressWarnings("hiding")
+ final Grid<?> grid = (Grid<?>) event.getSource();
+ label.setText("scrollTop: " + grid.getScrollTop()
+ + ", scrollLeft: " + grid.getScrollLeft());
+ }
+ });
+ }
+ }, listenersPath);
+ }
+
+ private void createStateMenu() {
+ String[] selectionModePath = { "Component", "State", "Selection mode" };
+ String[] primaryStyleNamePath = { "Component", "State",
+ "Primary Stylename" };
+
+ addMenuCommand("multi", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.setSelectionMode(SelectionMode.MULTI);
+ }
+ }, selectionModePath);
+
+ addMenuCommand("single", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.setSelectionMode(SelectionMode.SINGLE);
+ }
+ }, selectionModePath);
+
+ addMenuCommand("none", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.setSelectionMode(SelectionMode.NONE);
+ }
+ }, selectionModePath);
+
+ addMenuCommand("v-grid", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.setStylePrimaryName("v-grid");
+
+ }
+ }, primaryStyleNamePath);
+
+ addMenuCommand("v-escalator", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.setStylePrimaryName("v-escalator");
+
+ }
+ }, primaryStyleNamePath);
+
+ addMenuCommand("v-custom-style", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.setStylePrimaryName("v-custom-style");
+
+ }
+ }, primaryStyleNamePath);
+ }
+
+ private void createColumnsMenu() {
+
+ for (int i = 0; i < COLUMNS; i++) {
+ final int index = i;
+ final GridColumn<?, List<Data>> column = grid.getColumn(index);
+ addMenuCommand("Visible", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ column.setVisible(!column.isVisible());
+ }
+ }, "Component", "Columns", "Column " + i);
+ addMenuCommand("Sortable", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ column.setSortable(!column.isSortable());
+ }
+ }, "Component", "Columns", "Column " + i);
+ addMenuCommand("Frozen", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ if (column.equals(grid.getLastFrozenColumn())) {
+ grid.setLastFrozenColumn(null);
+ } else {
+ grid.setLastFrozenColumn(column);
+ }
+ }
+ }, "Component", "Columns", "Column " + i);
+
+ addMenuCommand("auto", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ column.setWidth(-1);
+ }
+ }, "Component", "Columns", "Column " + i, "Width");
+ addMenuCommand("50px", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ column.setWidth(50);
+ }
+ }, "Component", "Columns", "Column " + i, "Width");
+ addMenuCommand("200px", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ column.setWidth(200);
+ }
+ }, "Component", "Columns", "Column " + i, "Width");
+
+ // Header types
+ addMenuCommand("Text Header", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.getHeader().getRow(0).getCell(column)
+ .setText("Text Header");
+ }
+ }, "Component", "Columns", "Column " + i, "Header Type");
+ addMenuCommand("HTML Header", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.getHeader().getRow(0).getCell(column)
+ .setHtml("<b>HTML Header</b>");
+ }
+ }, "Component", "Columns", "Column " + i, "Header Type");
+ addMenuCommand("Widget Header", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ final Button button = new Button("Button Header");
+ button.addClickHandler(new ClickHandler() {
+
+ @Override
+ public void onClick(ClickEvent event) {
+ button.setText("Clicked");
+ }
+ });
+ grid.getHeader().getRow(0).getCell(column)
+ .setWidget(button);
+ }
+ }, "Component", "Columns", "Column " + i, "Header Type");
+
+ // Footer types
+ addMenuCommand("Text Footer", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.getFooter().getRow(0).getCell(column)
+ .setText("Text Footer");
+ }
+ }, "Component", "Columns", "Column " + i, "Footer Type");
+ addMenuCommand("HTML Footer", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.getFooter().getRow(0).getCell(column)
+ .setHtml("<b>HTML Footer</b>");
+ }
+ }, "Component", "Columns", "Column " + i, "Footer Type");
+ addMenuCommand("Widget Footer", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ final Button button = new Button("Button Footer");
+ button.addClickHandler(new ClickHandler() {
+
+ @Override
+ public void onClick(ClickEvent event) {
+ button.setText("Clicked");
+ }
+ });
+ grid.getFooter().getRow(0).getCell(column)
+ .setWidget(button);
+ }
+ }, "Component", "Columns", "Column " + i, "Footer Type");
+ }
+ }
+
+ private int headerCounter = 0;
+ private int footerCounter = 0;
+
+ private void setHeaderTexts(HeaderRow row) {
+ for (int i = 0; i < COLUMNS; ++i) {
+ String caption = "Header (" + headerCounter + "," + i + ")";
+
+ // Lets use some different cell types
+ if (i % 3 == 0) {
+ row.getCell(grid.getColumn(i)).setText(caption);
+ } else if (i % 2 == 0) {
+ row.getCell(grid.getColumn(i))
+ .setHtml("<b>" + caption + "</b>");
+ } else {
+ row.getCell(grid.getColumn(i)).setWidget(new HTML(caption));
+ }
+ }
+ headerCounter++;
+ }
+
+ private void setFooterTexts(FooterRow row) {
+ for (int i = 0; i < COLUMNS; ++i) {
+ String caption = "Footer (" + footerCounter + "," + i + ")";
+
+ // Lets use some different cell types
+ if (i % 3 == 0) {
+ row.getCell(grid.getColumn(i)).setText(caption);
+ } else if (i % 2 == 0) {
+ row.getCell(grid.getColumn(i))
+ .setHtml("<b>" + caption + "</b>");
+ } else {
+ row.getCell(grid.getColumn(i)).setWidget(new HTML(caption));
+ }
+ }
+ footerCounter++;
+ }
+
+ private void createHeaderMenu() {
+ final GridHeader header = grid.getHeader();
+ final String[] menuPath = { "Component", "Header" };
+
+ addMenuCommand("Visible", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ header.setVisible(!header.isVisible());
+ }
+ }, menuPath);
+
+ addMenuCommand("Top", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ header.setDefaultRow(header.getRow(0));
+ }
+ }, "Component", "Header", "Default row");
+ addMenuCommand("Bottom", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ header.setDefaultRow(header.getRow(header.getRowCount() - 1));
+ }
+ }, "Component", "Header", "Default row");
+ addMenuCommand("Unset", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ header.setDefaultRow(null);
+ }
+ }, "Component", "Header", "Default row");
+
+ addMenuCommand("Prepend row", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ configureHeaderRow(header.prependRow());
+ }
+ }, menuPath);
+ addMenuCommand("Append row", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ configureHeaderRow(header.appendRow());
+ }
+ }, menuPath);
+ addMenuCommand("Remove top row", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ header.removeRow(0);
+ }
+ }, menuPath);
+ addMenuCommand("Remove bottom row", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ header.removeRow(header.getRowCount() - 1);
+ }
+ }, menuPath);
+
+ }
+
+ private void configureHeaderRow(final HeaderRow row) {
+ final GridHeader header = grid.getHeader();
+ setHeaderTexts(row);
+ String rowTitle = "Row " + header.getRowCount();
+ final String[] menuPath = { "Component", "Header", rowTitle };
+
+ addMenuCommand("Join column cells 0, 1", new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ row.join(row.getCell(grid.getColumn(0)),
+ row.getCell(grid.getColumn(1)));
+
+ }
+ }, menuPath);
+
+ addMenuCommand("Join columns 1, 2", new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ row.join(grid.getColumn(1), grid.getColumn(2));
+
+ }
+ }, menuPath);
+
+ addMenuCommand("Join columns 3, 4, 5", new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ row.join(grid.getColumn(3), grid.getColumn(4),
+ grid.getColumn(5));
+
+ }
+ }, menuPath);
+
+ addMenuCommand("Join all columns", new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ row.join(grid.getColumns().toArray(
+ new GridColumn[grid.getColumnCount()]));
+
+ }
+ }, menuPath);
+ }
+
+ private void createFooterMenu() {
+ final GridFooter footer = grid.getFooter();
+ final String[] menuPath = { "Component", "Footer" };
+
+ addMenuCommand("Visible", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ footer.setVisible(!footer.isVisible());
+ }
+ }, menuPath);
+
+ addMenuCommand("Prepend row", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ configureFooterRow(footer.prependRow());
+ }
+ }, menuPath);
+ addMenuCommand("Append row", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ configureFooterRow(footer.appendRow());
+ }
+ }, menuPath);
+ addMenuCommand("Remove top row", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ footer.removeRow(0);
+ }
+ }, menuPath);
+ addMenuCommand("Remove bottom row", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ assert footer.getRowCount() > 0;
+ footer.removeRow(footer.getRowCount() - 1);
+ }
+ }, menuPath);
+ }
+
+ private void createEditorRowMenu() {
+ addMenuCommand("Enabled", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.getEditorRow()
+ .setEnabled(!grid.getEditorRow().isEnabled());
+ }
+ }, "Component", "Editor row");
+
+ addMenuCommand("Edit row 5", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.getEditorRow().editRow(5);
+ }
+ }, "Component", "Editor row");
+
+ addMenuCommand("Edit row 100", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.getEditorRow().editRow(100);
+ }
+ }, "Component", "Editor row");
+
+ addMenuCommand("Commit", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.getEditorRow().commit();
+ }
+ }, "Component", "Editor row");
+
+ addMenuCommand("Discard", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.getEditorRow().discard();
+ }
+ }, "Component", "Editor row");
+
+ addMenuCommand("Cancel edit", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ grid.getEditorRow().cancel();
+ }
+ }, "Component", "Editor row");
+
+ }
+
+ private void configureFooterRow(final FooterRow row) {
+ final GridFooter footer = grid.getFooter();
+ setFooterTexts(row);
+ String rowTitle = "Row " + footer.getRowCount();
+ final String[] menuPath = { "Component", "Footer", rowTitle };
+
+ addMenuCommand("Join column cells 0, 1", new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ row.join(row.getCell(grid.getColumn(0)),
+ row.getCell(grid.getColumn(1)));
+
+ }
+ }, menuPath);
+
+ addMenuCommand("Join columns 1, 2", new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ row.join(grid.getColumn(1), grid.getColumn(2));
+
+ }
+ }, menuPath);
+
+ addMenuCommand("Join all columns", new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ row.join(grid.getColumns().toArray(
+ new GridColumn[grid.getColumnCount()]));
+
+ }
+ }, menuPath);
+ }
+
+ /**
+ * Creates a renderer for a {@link Renderers}
+ */
+ @SuppressWarnings("rawtypes")
+ private final Renderer createRenderer(Renderers renderer) {
+ switch (renderer) {
+ case TEXT_RENDERER:
+ return new TextRenderer();
+
+ 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<Integer>();
+
+ case DATE_RENDERER:
+ return new DateRenderer();
+
+ default:
+ return new TextRenderer();
+ }
+ }
+
+ /**
+ * Creates a collection of handlers for all the grid key events
+ */
+ private void createKeyHandlers() {
+ final List<VLabel> labels = new ArrayList<VLabel>();
+ for (int i = 0; i < 9; ++i) {
+ VLabel tmp = new VLabel();
+ addNorth(tmp, 20);
+ labels.add(tmp);
+ }
+
+ // Key Down Events
+ grid.addBodyKeyDownHandler(new BodyKeyDownHandler() {
+ private final VLabel label = labels.get(0);
+
+ @Override
+ public void onKeyDown(GridKeyDownEvent event) {
+ updateLabel(label, event);
+ }
+ });
+
+ grid.addHeaderKeyDownHandler(new HeaderKeyDownHandler() {
+ private final VLabel label = labels.get(1);
+
+ @Override
+ public void onKeyDown(GridKeyDownEvent event) {
+ updateLabel(label, event);
+ }
+ });
+
+ grid.addFooterKeyDownHandler(new FooterKeyDownHandler() {
+ private final VLabel label = labels.get(2);
+
+ @Override
+ public void onKeyDown(GridKeyDownEvent event) {
+ updateLabel(label, event);
+ }
+ });
+
+ // Key Up Events
+ grid.addBodyKeyUpHandler(new BodyKeyUpHandler() {
+ private final VLabel label = labels.get(3);
+
+ @Override
+ public void onKeyUp(GridKeyUpEvent event) {
+ updateLabel(label, event);
+ }
+ });
+
+ grid.addHeaderKeyUpHandler(new HeaderKeyUpHandler() {
+ private final VLabel label = labels.get(4);
+
+ @Override
+ public void onKeyUp(GridKeyUpEvent event) {
+ updateLabel(label, event);
+ }
+ });
+
+ grid.addFooterKeyUpHandler(new FooterKeyUpHandler() {
+ private final VLabel label = labels.get(5);
+
+ @Override
+ public void onKeyUp(GridKeyUpEvent event) {
+ updateLabel(label, event);
+ }
+ });
+
+ // Key Press Events
+ grid.addBodyKeyPressHandler(new BodyKeyPressHandler() {
+ private final VLabel label = labels.get(6);
+
+ @Override
+ public void onKeyPress(GridKeyPressEvent event) {
+ updateLabel(label, event);
+ }
+ });
+
+ grid.addHeaderKeyPressHandler(new HeaderKeyPressHandler() {
+ private final VLabel label = labels.get(7);
+
+ @Override
+ public void onKeyPress(GridKeyPressEvent event) {
+ updateLabel(label, event);
+ }
+ });
+
+ grid.addFooterKeyPressHandler(new FooterKeyPressHandler() {
+ private final VLabel label = labels.get(8);
+
+ @Override
+ public void onKeyPress(GridKeyPressEvent event) {
+ updateLabel(label, event);
+ }
+ });
+
+ }
+
+ private void updateLabel(VLabel label, AbstractGridKeyEvent<?> event) {
+ String type = event.getNativeEvent().getType();
+ Cell active = event.getActiveCell();
+ String coords = "(" + active.getRow() + ", " + active.getColumn() + ")";
+ String keyCode = "" + event.getNativeKeyCode();
+ label.setText(coords + " " + type + " " + keyCode);
+ }
+}
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
index 0000000000..f4ca1d0344
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java
@@ -0,0 +1,380 @@
+/*
+ * 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.Comparator;
+import java.util.Date;
+import java.util.List;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.Window.Location;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.vaadin.client.data.DataChangeHandler;
+import com.vaadin.client.data.DataSource;
+import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.client.ui.grid.Cell;
+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.datasources.ListSorter;
+import com.vaadin.client.ui.grid.renderers.ComplexRenderer;
+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.client.ui.grid.sort.Sort;
+import com.vaadin.client.ui.grid.sort.SortEvent;
+import com.vaadin.client.ui.grid.sort.SortEventHandler;
+import com.vaadin.client.ui.grid.sort.SortOrder;
+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, CPLX_RENDERER;
+ }
+
+ /**
+ * Datasource for simulating network latency
+ */
+ private class DelayedDataSource implements DataSource<String> {
+
+ private DataSource<String> ds;
+ private int firstRowIndex = -1;
+ private int numberOfRows;
+ private DataChangeHandler dataChangeHandler;
+ private int latency;
+
+ public DelayedDataSource(DataSource<String> ds, int latency) {
+ this.ds = ds;
+ this.latency = latency;
+ }
+
+ @Override
+ public void ensureAvailability(final int firstRowIndex,
+ final int numberOfRows) {
+ new Timer() {
+
+ @Override
+ public void run() {
+ DelayedDataSource.this.firstRowIndex = firstRowIndex;
+ DelayedDataSource.this.numberOfRows = numberOfRows;
+ dataChangeHandler.dataUpdated(firstRowIndex, numberOfRows);
+ dataChangeHandler
+ .dataAvailable(firstRowIndex, numberOfRows);
+ }
+ }.schedule(latency);
+ }
+
+ @Override
+ public String getRow(int rowIndex) {
+ if (rowIndex >= firstRowIndex
+ && rowIndex <= firstRowIndex + numberOfRows) {
+ return ds.getRow(rowIndex);
+ }
+ return null;
+ }
+
+ @Override
+ public int getEstimatedSize() {
+ return ds.getEstimatedSize();
+ }
+
+ @Override
+ public void setDataChangeHandler(DataChangeHandler dataChangeHandler) {
+ this.dataChangeHandler = dataChangeHandler;
+ }
+
+ @Override
+ public RowHandle<String> getHandle(String row) {
+ // TODO Auto-generated method stub (henrik paul: 17.6.)
+ return null;
+ }
+ }
+
+ @Override
+ protected void init() {
+ Grid<String> grid = getWidget();
+ grid.setSelectionMode(Grid.SelectionMode.NONE);
+
+ // 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
+ if (Location.getParameter("latency") != null) {
+ grid.setDataSource(new DelayedDataSource(
+ new ListDataSource<String>(columnData), Integer
+ .parseInt(Location.getParameter("latency"))));
+ } else {
+ grid.setDataSource(new ListDataSource<String>(columnData));
+ }
+
+ // Add a column to display the data in
+ GridColumn<String, String> c = createColumnWithRenderer(Renderers.TEXT_RENDERER);
+ grid.addColumn(c);
+ grid.getHeader().getDefaultRow().getCell(c).setText("Column 1");
+
+ // Add another column with a custom complex renderer
+ c = createColumnWithRenderer(Renderers.CPLX_RENDERER);
+ grid.addColumn(c);
+ grid.getHeader().getDefaultRow().getCell(c).setText("Column 2");
+
+ // Add method for testing sort event firing
+ grid.addSortHandler(new SortEventHandler<String>() {
+ @Override
+ public void sort(SortEvent<String> event) {
+ Element console = Document.get().getElementById(
+ "testDebugConsole");
+ String text = "Client-side sort event received<br>"
+ + "Columns: " + event.getOrder().size() + ", order: ";
+ for (SortOrder order : event.getOrder()) {
+ String columnHeader = getWidget().getHeader()
+ .getDefaultRow().getCell(order.getColumn())
+ .getText();
+ text += columnHeader + ": "
+ + order.getDirection().toString();
+ }
+ console.setInnerHTML(text);
+ }
+ });
+
+ // Handle RPC calls
+ registerRpc(GridClientColumnRendererRpc.class,
+ new GridClientColumnRendererRpc() {
+
+ @Override
+ public void addColumn(Renderers renderer) {
+
+ GridColumn<?, String> column;
+ if (renderer == Renderers.NUMBER_RENDERER) {
+ column = createNumberColumnWithRenderer(renderer);
+ } else if (renderer == Renderers.DATE_RENDERER) {
+ column = createDateColumnWithRenderer(renderer);
+ } else {
+ column = createColumnWithRenderer(renderer);
+ }
+ getWidget().addColumn(column);
+
+ getWidget()
+ .getHeader()
+ .getDefaultRow()
+ .getCell(column)
+ .setText(
+ "Column "
+ + String.valueOf(getWidget()
+ .getColumnCount() + 1));
+ }
+
+ @Override
+ public void detachAttach() {
+
+ // Detach
+ HasWidgets parent = (HasWidgets) getWidget()
+ .getParent();
+ parent.remove(getWidget());
+
+ // Re-attach
+ parent.add(getWidget());
+ }
+
+ @Override
+ public void triggerClientSorting() {
+ getWidget().sort(Sort.by(getWidget().getColumn(0)));
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void triggerClientSortingTest() {
+ Grid<String> grid = getWidget();
+ ListSorter<String> sorter = new ListSorter<String>(grid);
+
+ // Make sorter sort the numbers in natural order
+ sorter.setComparator(
+ (GridColumn<String, String>) grid.getColumn(0),
+ new Comparator<String>() {
+ @Override
+ public int compare(String o1, String o2) {
+ return Integer.parseInt(o1)
+ - Integer.parseInt(o2);
+ }
+ });
+
+ // Sort along column 0 in ascending order
+ grid.sort(grid.getColumn(0));
+
+ // Remove the sorter once we're done
+ sorter.removeFromGrid();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void shuffle() {
+ Grid<String> grid = getWidget();
+ ListSorter<String> shuffler = new ListSorter<String>(
+ grid);
+
+ // Make shuffler return random order
+ shuffler.setComparator(
+ (GridColumn<String, String>) grid.getColumn(0),
+ new Comparator<String>() {
+ @Override
+ public int compare(String o1, String o2) {
+ return com.google.gwt.user.client.Random
+ .nextInt(3) - 1;
+ }
+ });
+
+ // "Sort" (actually shuffle) along column 0
+ grid.sort(grid.getColumn(0));
+
+ // Remove the shuffler when we're done so that it
+ // doesn't interfere with further operations
+ shuffler.removeFromGrid();
+ }
+ });
+ }
+
+ /**
+ * 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() {
+ final Button button = new Button("");
+ button.addClickHandler(new ClickHandler() {
+
+ @Override
+ public void onClick(ClickEvent event) {
+ button.setText("Clicked");
+ }
+ });
+ return button;
+ }
+
+ @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();
+
+ case CPLX_RENDERER:
+ return new ComplexRenderer<String>() {
+
+ @Override
+ public void render(FlyweightCell cell, String data) {
+ cell.getElement().setInnerHTML("<span>" + data + "</span>");
+ cell.getElement().getStyle().clearBackgroundColor();
+ }
+
+ @Override
+ public void setContentVisible(FlyweightCell cell,
+ boolean hasData) {
+
+ // Visualize content visible property
+ cell.getElement().getStyle()
+ .setBackgroundColor(hasData ? "green" : "red");
+
+ super.setContentVisible(cell, hasData);
+ }
+
+ @Override
+ public boolean onActivate(Cell cell) {
+ cell.getElement().setInnerHTML("<span>Activated!</span>");
+ return true;
+ }
+ };
+
+ 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
index 0000000000..90eee9e1c6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java
@@ -0,0 +1,48 @@
+/*
+ * 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();
+
+ /**
+ * Used for client-side sorting API test
+ */
+ void triggerClientSorting();
+
+ /**
+ * @since
+ */
+ void triggerClientSortingTest();
+
+ /**
+ * @since
+ */
+ void shuffle();
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java
new file mode 100644
index 0000000000..d6873ac0a5
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java
@@ -0,0 +1,46 @@
+/*
+ * 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.client.ui.grid.FlyweightCell;
+import com.vaadin.client.ui.grid.Renderer;
+import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector;
+import com.vaadin.shared.ui.Connect;
+
+@Connect(com.vaadin.tests.components.grid.IntArrayRenderer.class)
+public class IntArrayRendererConnector extends AbstractRendererConnector<int[]> {
+
+ public static class IntArrayRenderer implements Renderer<int[]> {
+ private static final String JOINER = " :: ";
+
+ @Override
+ public void render(FlyweightCell cell, int[] data) {
+ String text = "";
+ for (int i : data) {
+ text += i + JOINER;
+ }
+ if (!text.isEmpty()) {
+ text = text.substring(0, text.length() - JOINER.length());
+ }
+ cell.getElement().setInnerText(text);
+ }
+ }
+
+ @Override
+ public IntArrayRenderer getRenderer() {
+ return (IntArrayRenderer) super.getRenderer();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/PureGWTTestApplication.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/PureGWTTestApplication.java
new file mode 100644
index 0000000000..e9c126f232
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/PureGWTTestApplication.java
@@ -0,0 +1,308 @@
+/*
+ * 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.List;
+
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.DockLayoutPanel;
+import com.google.gwt.user.client.ui.LayoutPanel;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.Panel;
+import com.vaadin.client.ui.SubPartAware;
+
+/**
+ * Pure GWT Test Application base for testing features of a single widget;
+ * provides a menu system and convenience method for adding items to it.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public abstract class PureGWTTestApplication<T> extends DockLayoutPanel
+ implements SubPartAware {
+
+ /**
+ * Class describing a menu item with an associated action
+ */
+ public static class Command {
+ private final String title;
+ private final ScheduledCommand command;
+
+ /**
+ * Creates a Command object, which is used as an action entry in the
+ * Menu
+ *
+ * @param t
+ * a title string
+ * @param cmd
+ * a scheduled command that is executed when this item is
+ * selected
+ */
+ public Command(String t, ScheduledCommand cmd) {
+ title = t;
+ command = cmd;
+ }
+
+ /**
+ * Returns the title of this command item
+ *
+ * @return a title string
+ */
+ public final String getTitle() {
+ return title;
+ }
+
+ /**
+ * Returns the actual scheduled command of this command item
+ *
+ * @return a scheduled command
+ */
+ public final ScheduledCommand getCommand() {
+ return command;
+ }
+ }
+
+ /**
+ * A menu object, providing a complete system for building a hierarchical
+ * menu bar system.
+ */
+ public static class Menu {
+
+ private final String title;
+ private final MenuBar menubar;
+ private final List<Menu> children;
+ private final List<Command> items;
+
+ /**
+ * Create base-level menu, without a title. This is the root menu bar,
+ * which can be attached to a client application window. All other Menus
+ * should be added as child menus to this Menu, in order to maintain a
+ * nice hierarchy.
+ */
+ private Menu() {
+ title = "";
+ menubar = new MenuBar();
+ children = new ArrayList<Menu>();
+ items = new ArrayList<Command>();
+ }
+
+ /**
+ * Create a sub-menu, with a title.
+ *
+ * @param title
+ */
+ public Menu(String title) {
+ this.title = title;
+ menubar = new MenuBar(true);
+ children = new ArrayList<Menu>();
+ items = new ArrayList<Command>();
+ }
+
+ /**
+ * Return the GWT {@link MenuBar} object that provides the widget for
+ * this Menu
+ *
+ * @return a menubar object
+ */
+ public MenuBar getMenuBar() {
+ return menubar;
+ }
+
+ /**
+ * Returns the title of this menu entry
+ *
+ * @return a title string
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Adds a child menu entry to this menu. The title for this entry is
+ * taken from the Menu object argument.
+ *
+ * @param m
+ * another Menu object
+ */
+ public void addChildMenu(Menu m) {
+ menubar.addItem(m.title, m.menubar);
+ children.add(m);
+ }
+
+ /**
+ * Tests for the existence of a child menu by title at this level of the
+ * menu hierarchy
+ *
+ * @param title
+ * a title string
+ * @return true, if this menu has a direct child menu with the specified
+ * title, otherwise false
+ */
+ public boolean hasChildMenu(String title) {
+ return getChildMenu(title) != null;
+ }
+
+ /**
+ * Gets a reference to a child menu with a certain title, that is a
+ * direct child of this menu level.
+ *
+ * @param title
+ * a title string
+ * @return a Menu object with the specified title string, or null, if
+ * this menu doesn't have a direct child with the specified
+ * title.
+ */
+ public Menu getChildMenu(String title) {
+ for (Menu m : children) {
+ if (m.title.equals(title)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds a command item to the menu. When the entry is clicked, the
+ * command is executed.
+ *
+ * @param cmd
+ * a command object.
+ */
+ public void addCommand(Command cmd) {
+ menubar.addItem(cmd.title, cmd.command);
+ items.add(cmd);
+ }
+
+ /**
+ * Tests for the existence of a {@link Command} that is the direct child
+ * of this level of menu.
+ *
+ * @param title
+ * the command's title
+ * @return true, if this menu level includes a command item with the
+ * specified title. Otherwise false.
+ */
+ public boolean hasCommand(String title) {
+ return getCommand(title) != null;
+ }
+
+ /**
+ * Gets a reference to a {@link Command} item that is the direct child
+ * of this level of menu.
+ *
+ * @param title
+ * the command's title
+ * @return a command, if found in this menu level, otherwise null.
+ */
+ public Command getCommand(String title) {
+ for (Command c : items) {
+ if (c.title.equals(title)) {
+ return c;
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Base level menu object, provides visible menu bar
+ */
+ private final Menu menu;
+ private final T testedWidget;
+
+ /**
+ * This constructor creates the basic menu bar and adds it to the top of the
+ * parent {@link DockLayoutPanel}
+ */
+ protected PureGWTTestApplication(T widget) {
+ super(Unit.PX);
+ Panel menuPanel = new LayoutPanel();
+ menu = new Menu();
+ menuPanel.add(menu.getMenuBar());
+ addNorth(menuPanel, 25);
+ testedWidget = widget;
+ }
+
+ /**
+ * Connect an item to the menu structure
+ *
+ * @param cmd
+ * a scheduled command; see google's docs
+ * @param menupath
+ * path to the item
+ */
+ public void addMenuCommand(String title, ScheduledCommand cmd,
+ String... menupath) {
+ Menu m = createMenuPath(menupath);
+
+ m.addCommand(new Command(title, cmd));
+ }
+
+ /**
+ * Create a menu path, if one doesn't already exist, and return the last
+ * menu in the series.
+ *
+ * @param path
+ * a varargs list or array of strings describing a menu path,
+ * e.g. "File", "Recent", "User Files", which would result in the
+ * File menu having a submenu called "Recent" which would have a
+ * submenu called "User Files".
+ * @return the last Menu object specified by the path
+ */
+ private Menu createMenuPath(String... path) {
+ Menu m = menu;
+
+ for (String p : path) {
+ Menu sub = m.getChildMenu(p);
+
+ if (sub == null) {
+ sub = new Menu(p);
+ m.addChildMenu(sub);
+ }
+ m = sub;
+ }
+
+ return m;
+ }
+
+ @Override
+ public Element getSubPartElement(String subPart) {
+ if (testedWidget instanceof SubPartAware) {
+ return ((SubPartAware) testedWidget).getSubPartElement(subPart);
+ }
+ return null;
+ }
+
+ @Override
+ public String getSubPartName(Element subElement) {
+ if (testedWidget instanceof SubPartAware) {
+ return ((SubPartAware) testedWidget).getSubPartName(subElement);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the tested widget.
+ *
+ * @return tested widget
+ */
+ public T getTestedWidget() {
+ return testedWidget;
+ }
+}
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..3880bacae2
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java
@@ -0,0 +1,76 @@
+/*
+ * 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 boolean 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);
+ return true;
+ }
+ }
+
+ @Override
+ protected Renderer<Void> createRenderer() {
+ // cannot use the default createRenderer as RowAwareRenderer needs a
+ // reference to its connector - it has no "real" no-argument constructor
+ return new RowAwareRenderer();
+ }
+}
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
index 0000000000..db931888bc
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java
@@ -0,0 +1,153 @@
+/*
+ * 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.shared.ui.label.ContentMode;
+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.Label;
+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();
+ }
+
+ /**
+ * @since
+ */
+ public void triggerClientSorting() {
+ rpc().triggerClientSorting();
+ }
+
+ /**
+ * @since
+ */
+ public void triggerClientSortingTest() {
+ rpc().triggerClientSortingTest();
+ }
+
+ /**
+ * @since
+ */
+ public void shuffle() {
+ rpc().shuffle();
+ }
+ }
+
+ @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);
+
+ NativeButton shuffleButton = new NativeButton("Shuffle");
+ shuffleButton.addClickListener(new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ controller.shuffle();
+ }
+ });
+ controls.addComponent(shuffleButton);
+
+ NativeButton sortButton = new NativeButton("Trigger sorting event");
+ sortButton.addClickListener(new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ controller.triggerClientSorting();
+ }
+ });
+ controls.addComponent(sortButton);
+
+ NativeButton testSortingButton = new NativeButton("Test sorting");
+ testSortingButton.addClickListener(new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ controller.triggerClientSortingTest();
+ }
+ });
+ controls.addComponent(testSortingButton);
+
+ Label console = new Label();
+ console.setContentMode(ContentMode.HTML);
+ console.setId("testDebugConsole");
+ content.addComponent(console);
+ }
+}