From 9b510d35a7ec6b1a9504343b2620110b77d4e5c3 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Tue, 18 Mar 2014 16:36:10 +0200 Subject: Adds setHeightByRow support to Grid (#13297) Change-Id: I67f1bfb476a8af28c0ea1a03758684ca42d1ba48 --- .../tests/components/grid/GridBasicFeatures.java | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index c28feb8d10..0faabff88a 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -15,11 +15,13 @@ */ package com.vaadin.tests.components.grid; +import java.text.DecimalFormat; import java.util.ArrayList; import java.util.LinkedHashMap; import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; +import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.tests.components.AbstractComponentTest; import com.vaadin.ui.components.grid.ColumnGroup; import com.vaadin.ui.components.grid.ColumnGroupRow; @@ -86,6 +88,8 @@ public class GridBasicFeatures extends AbstractComponentTest { createRowActions(); + addHeightByRowActions(); + return grid; } @@ -330,6 +334,41 @@ public class GridBasicFeatures extends AbstractComponentTest { }, null); } + @SuppressWarnings("boxing") + protected void addHeightByRowActions() { + createCategory("Height by Rows", "Size"); + + createBooleanAction("HeightMode Row", "Size", false, + new Command() { + @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); + } + } + + private void addActionForHeightByRows(final Double i) { + DecimalFormat df = new DecimalFormat("0.00"); + createClickAction(df.format(i) + " rows", "Height by Rows", + new Command() { + @Override + public void execute(Grid c, String value, Object data) { + c.setHeightByRows(i); + } + }, null); + } + @Override protected Integer getTicketNumber() { return 12829; -- cgit v1.2.3 From 66f08e6eef91d26a674e21170a4b3a6885442764 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Tue, 18 Mar 2014 17:46:18 +0200 Subject: Added some forgotten logic to Escalator for Grid to work at all (#13334) Change-Id: Ia52e7225062f3331a9b136fbd40d5a81e6e81f96 --- .../src/com/vaadin/client/ui/grid/Escalator.java | 4 ++ .../components/grid/GridBasicFeaturesTest.java | 49 ++++++++++++++++++++++ 2 files changed, 53 insertions(+) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index c269404990..787631fb24 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -1969,6 +1969,8 @@ public class Escalator extends Widget { logicalRowIndex); updateTopRowLogicalIndex(-originalRowsToMove); + + rowsWereMoved = true; } else if (viewportOffset + getDefaultRowHeight() <= 0) { @@ -2062,6 +2064,8 @@ public class Escalator extends Widget { - visualRowOrder.size(); setTopRowLogicalIndex(Math.min(naiveNewLogicalIndex, maxLogicalIndex)); + + rowsWereMoved = true; } if (rowsWereMoved) { diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index bc43f2be98..b260cdd3a1 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -22,7 +22,9 @@ import java.util.List; import org.junit.Test; import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; @@ -295,6 +297,29 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { "modified: Column0", getBodyCellByRowAndColumn(1, 1).getText()); } + @Test + public void testDataFetchingWorks() throws Exception { + openTestURL(); + + scrollGridVerticallyTo(200); + + /* + * Give time for the data to be fetched. + * + * TODO TestBench currently doesn't know when Grid's DOM structure is + * stable. There are some plans regarding implementing support for this, + * so this test case can (should) be modified once that's implemented. + */ + sleep(1000); + + /* + * TODO this screenshot comparison could be done on the DOM level, if + * the DOM would be always in order. This could be amended once DOM + * reordering is merged into the Grid branch. + */ + compareScreen("dataHasBeenLoaded"); + } + private boolean elementIsFound(By locator) { try { return driver.findElement(locator) != null; @@ -370,4 +395,28 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { return getDriver().findElements( By.xpath("//div[@id='testComponent']//tfoot//td")); } + + private void scrollGridVerticallyTo(double px) { + executeScript("arguments[0].scrollTop = " + px, + getGridVerticalScrollbar()); + } + + private Object executeScript(String script, WebElement element) { + @SuppressWarnings("hiding") + 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()); + } + } + + private WebElement getGridVerticalScrollbar() { + return getDriver() + .findElement( + By.xpath("//div[contains(@class, \"v-grid-scroller-vertical\")]")); + } } -- cgit v1.2.3 From 55ab9980811c52735a0ee1943907327f5ca0fcd8 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Tue, 29 Apr 2014 11:33:17 +0300 Subject: Added test for previously fixed state ordering issue #13334 Test for fix submitted in 3cba005. Change-Id: I92ee775403cbfb315499f2bcab90c895bf734832 --- .../tests/components/grid/GridSingleColumn.java | 57 ++++++++++++++++++++++ .../components/grid/GridSingleColumnTest.java | 38 +++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java (limited to 'uitest/src') 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..08b4f0c0d7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2013 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.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); + + 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..9c1ec88df7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2013 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.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class GridSingleColumnTest extends MultiBrowserTest { + + @Test + 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")); + } +} -- cgit v1.2.3 From c52b4a3d3967b2eefb8c8e1c287f8dd587f7c4f9 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Fri, 25 Apr 2014 14:24:56 +0300 Subject: Made grid testbench tests more stable on all browsers Testbench reports different things for the css width depending on the browser so changed the tests to use the WebElement.Size property instead to get consistant results. Also removed the data change test as in its current state it does not serve any purpose. A similar test could be added at some point when we actually can test this. The test had never succeeded. Change-Id: I8d762b1c662afb5e9b09d384b8100200fbfaba33 --- .../components/grid/GridBasicFeaturesTest.java | 52 +++------------------- 1 file changed, 7 insertions(+), 45 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index b260cdd3a1..7163fbea75 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -184,58 +184,43 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { public void testInitialColumnWidths() throws Exception { openTestURL(); - // Default borders and margins implemented by escalator - int cellBorder = 1 + 1; - int cellMargin = 2 + 2; - WebElement cell = getBodyCellByRowAndColumn(1, 1); - assertEquals((100 - cellBorder - cellMargin) + "px", - cell.getCssValue("width")); + assertEquals(100, cell.getSize().getWidth()); cell = getBodyCellByRowAndColumn(1, 2); - assertEquals((150 - cellBorder - cellMargin) + "px", - cell.getCssValue("width")); + assertEquals(150, cell.getSize().getWidth()); cell = getBodyCellByRowAndColumn(1, 3); - assertEquals((200 - cellBorder - cellMargin) + "px", - cell.getCssValue("width")); + assertEquals(200, cell.getSize().getWidth()); } @Test public void testColumnWidths() throws Exception { openTestURL(); - // Default borders and margins implemented by escalator - int cellBorder = 1 + 1; - int cellMargin = 2 + 2; - // Default column width is 100px WebElement cell = getBodyCellByRowAndColumn(1, 1); - assertEquals((100 - cellBorder - cellMargin) + "px", - cell.getCssValue("width")); + assertEquals(100, cell.getSize().getWidth()); // Set first column to be 200px wide selectMenuPath("Component", "Columns", "Column0", "Column0 Width", "200px"); cell = getBodyCellByRowAndColumn(1, 1); - assertEquals((200 - cellBorder - cellMargin) + "px", - cell.getCssValue("width")); + assertEquals(200, cell.getSize().getWidth()); // Set second column to be 150px wide selectMenuPath("Component", "Columns", "Column1", "Column1 Width", "150px"); cell = getBodyCellByRowAndColumn(1, 2); - assertEquals((150 - cellBorder - cellMargin) + "px", - cell.getCssValue("width")); + assertEquals(150, cell.getSize().getWidth()); // Set first column to be auto sized (defaults to 100px currently) selectMenuPath("Component", "Columns", "Column0", "Column0 Width", "Auto"); cell = getBodyCellByRowAndColumn(1, 1); - assertEquals((100 - cellBorder - cellMargin) + "px", - cell.getCssValue("width")); + assertEquals(100, cell.getSize().getWidth()); } @Test @@ -297,29 +282,6 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { "modified: Column0", getBodyCellByRowAndColumn(1, 1).getText()); } - @Test - public void testDataFetchingWorks() throws Exception { - openTestURL(); - - scrollGridVerticallyTo(200); - - /* - * Give time for the data to be fetched. - * - * TODO TestBench currently doesn't know when Grid's DOM structure is - * stable. There are some plans regarding implementing support for this, - * so this test case can (should) be modified once that's implemented. - */ - sleep(1000); - - /* - * TODO this screenshot comparison could be done on the DOM level, if - * the DOM would be always in order. This could be amended once DOM - * reordering is merged into the Grid branch. - */ - compareScreen("dataHasBeenLoaded"); - } - private boolean elementIsFound(By locator) { try { return driver.findElement(locator) != null; -- cgit v1.2.3 From db09b916b8222519a7e51dcb656cb092bec29e55 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Mon, 28 Apr 2014 11:55:09 +0300 Subject: Hide visual debugging from BasicEscalator by default (#13334) Because this debugging info can reveal things that might vary a bit on small internal modifications in Escalator, I've decided to hide this information instead. The performance effects are negligible. All the old goodies can be reintroduced by adding a "pretty" GET parameter, if you so wish. Also, converted a (faulty) TB2 test into TB3. Change-Id: Icf25190e668ea9175090edba51e6d61a23007633 --- .../tests/components/grid/BasicEscalator.html | 176 --------------------- .../tests/components/grid/BasicEscalatorTest.java | 107 ++++++++++++- .../tests/widgetset/client/grid/VTestGrid.java | 37 +++-- 3 files changed, 126 insertions(+), 194 deletions(-) delete mode 100644 uitest/src/com/vaadin/tests/components/grid/BasicEscalator.html (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.html b/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.html deleted file mode 100644 index 70aa0fe195..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - -BasicEscalator - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BasicEscalator
open/run/com.vaadin.tests.components.grid.BasicEscalator?restartApplication
verifyTextvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]Row 0: 0,0 (0)
verifyTextvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[17]/domChild[9]Cell: 9,17 (179)
verifyTextNotPresentCell: 0,100
verifyTextNotPresentCell: 0,101
typevaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[0]/VTextField[0]0
typevaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[1]/VTextField[0]1
clickvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]
verifyTextvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[18]/domChild[0]Row 0: 0,100 (190)
typevaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[0]/VTextField[0]11
clickvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]
verifyTextvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[17]/domChild[0]Row 11: 0,101 (200)
typevaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[0]/VTextField[0]0
typevaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[1]/VTextField[0]100
clickvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]
verifyTextvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[16]/domChild[0]Row 0: 0,102 (210)
verifyTextvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[0]Row 16: 0,118 (370)
scrollvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[0]1109
verifyTextPresentRow 56: 0,158
verifyTextPresentRow 72: 0,174
scrollvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[0]3690
verifyTextPresentRow 201: 0,99
typevaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VHorizontalLayout[0]/Slot[0]/VTextField[0]201
typevaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VHorizontalLayout[0]/Slot[1]/VTextField[0]1
clickvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VHorizontalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]
verifyTextvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[0]Row 200: 0,98 (960)
verifyTextNotPresentRow 201:
typevaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VHorizontalLayout[0]/Slot[0]/VTextField[0]0
typevaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VHorizontalLayout[0]/Slot[1]/VTextField[0]2
clickvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VHorizontalLayout[0]/Slot[2]/VButton[0]
verifyTextvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[16]/domChild[0]Row 184: 10,82 (974)
verifyTextvaadin=runcomvaadintestscomponentsgridBasicEscalator::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTestGrid[0]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[0]Row 200: 10,98 (1006)
- - diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java index 5afe826196..bd1a580c73 100644 --- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java @@ -15,8 +15,15 @@ */ package com.vaadin.tests.components.grid; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + import org.junit.Test; import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import com.vaadin.tests.tb3.MultiBrowserTest; @@ -24,20 +31,88 @@ import com.vaadin.tests.tb3.MultiBrowserTest; public class BasicEscalatorTest extends MultiBrowserTest { @Test - public void testNormalHeight() throws Exception { + public void testInitialState() throws Exception { + openTestURL(); + + WebElement cell1 = getBodyRowCell(0, 0); + assertEquals("Top left body cell had unexpected content", "Row 0: 0,0", + cell1.getText()); + + WebElement cell2 = getBodyRowCell(15, 3); + assertEquals("Lower merged cell had unexpected content", "Cell: 3,15", + cell2.getText()); + } + + @Test + public void testScroll() throws Exception { + openTestURL(); + + /* + * let the DOM stabilize itself. TODO: remove once waitForVaadin + * supports lazy loaded components + */ + Thread.sleep(100); + + scrollEscalatorVerticallyTo(1000); + assertBodyCellWithContentIsFound("Row 50: 0,50"); + } + + @Test + public void testLastRow() throws Exception { + openTestURL(); + + /* + * let the DOM stabilize itself. TODO: remove once waitForVaadin + * supports lazy loaded components + */ + Thread.sleep(100); + + // scroll to bottom + scrollEscalatorVerticallyTo(100000000); + + /* + * this test does not test DOM reordering, therefore we don't rely on + * child indices - we simply seek by content. + */ + assertBodyCellWithContentIsFound("Row 99: 0,99"); + } + + @Test + public void testNormalRowHeight() throws Exception { + /* + * This is tested with screenshots instead of CSS queries, since some + * browsers report dimensions differently from each other, which is + * uninteresting for our purposes + */ openTestURL(); compareScreen("normalHeight"); } @Test - public void testModifiedHeight() throws Exception { + public void testModifiedRowHeight() throws Exception { + /* + * This is tested with screenshots instead of CSS queries, since some + * browsers report dimensions differently from each other, which is + * uninteresting for our purposes + */ openTestURLWithTheme("reindeer-tests"); compareScreen("modifiedHeight"); } - private WebElement getFirstBodyRowCell() { + private void assertBodyCellWithContentIsFound(String cellContent) { + String xpath = "//tbody/tr/td[.='" + cellContent + "']"; + try { + assertNotNull("received a null element with \"" + xpath + "\"", + getDriver().findElement(By.xpath(xpath))); + } catch (NoSuchElementException e) { + fail("Could not find '" + xpath + "'"); + } + } + + private WebElement getBodyRowCell(int row, int col) { return getDriver().findElement( - By.xpath("//tbody/tr[@class='v-escalator-row'][1]/td[1]")); + By.xpath("//tbody/tr[@class='v-escalator-row'][" + (row + 1) + + "]/td[" + (col + 1) + "]")); } private void openTestURLWithTheme(String themeName) { @@ -46,4 +121,28 @@ public class BasicEscalatorTest extends MultiBrowserTest { testUrl += "theme=" + themeName; getDriver().get(testUrl); } + + private void scrollEscalatorVerticallyTo(double px) { + executeScript("arguments[0].scrollTop = " + px, + getGridVerticalScrollbar()); + } + + private Object executeScript(String script, WebElement element) { + @SuppressWarnings("hiding") + 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()); + } + } + + private WebElement getGridVerticalScrollbar() { + return getDriver() + .findElement( + By.xpath("//div[contains(@class, \"v-escalator-scroller-vertical\")]")); + } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java index 28e650edc1..bdbff4a6f0 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java @@ -3,6 +3,7 @@ package com.vaadin.tests.widgetset.client.grid; import java.util.ArrayList; import java.util.List; +import com.google.gwt.user.client.Window.Location; import com.google.gwt.user.client.ui.Composite; import com.vaadin.client.ui.grid.Cell; import com.vaadin.client.ui.grid.ColumnConfiguration; @@ -81,8 +82,10 @@ public class VTestGrid extends Composite { public void renderCell(final Cell cell) { final Integer columnName = columns.get(cell.getColumn()); final Integer rowName = rows.get(cell.getRow()); - final String cellInfo = columnName + "," + rowName + " (" - + i + ")"; + String cellInfo = columnName + "," + rowName; + if (shouldRenderPretty()) { + cellInfo += " (" + i + ")"; + } if (cell.getColumn() > 0) { cell.getElement().setInnerText("Cell: " + cellInfo); @@ -95,23 +98,29 @@ public class VTestGrid extends Composite { cell.setColSpan(3); } - final double c = i * .1; - final int r = (int) ((Math.cos(c) + 1) * 128); - final int g = (int) ((Math.cos(c / Math.PI) + 1) * 128); - final int b = (int) ((Math.cos(c / (Math.PI * 2)) + 1) * 128); - cell.getElement() - .getStyle() - .setBackgroundColor( - "rgb(" + r + "," + g + "," + b + ")"); - if ((r * .8 + g * 1.3 + b * .9) / 3 < 127) { - cell.getElement().getStyle().setColor("white"); - } else { - cell.getElement().getStyle().clearColor(); + if (shouldRenderPretty()) { + final double c = i * .1; + final int r = (int) ((Math.cos(c) + 1) * 128); + final int g = (int) ((Math.cos(c / Math.PI) + 1) * 128); + final int b = (int) ((Math.cos(c / (Math.PI * 2)) + 1) * 128); + cell.getElement() + .getStyle() + .setBackgroundColor( + "rgb(" + r + "," + g + "," + b + ")"); + if ((r * .8 + g * 1.3 + b * .9) / 3 < 127) { + cell.getElement().getStyle().setColor("white"); + } else { + cell.getElement().getStyle().clearColor(); + } } i++; } + private boolean shouldRenderPretty() { + return Location.getQueryString().contains("pretty"); + } + @Override public void updateCells(final Row row, final Iterable cellsToUpdate) { -- cgit v1.2.3 From 335eb7937d29c4b540b9bd2e02651e11ff46a6ba Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Wed, 30 Apr 2014 11:47:57 +0300 Subject: Fixed NPE after columns have been removed #13334 The indexes were never updated for the columns so after columns was removed and new data was fetched an ArrayOutOfBounds exception could occur. To fix this we use the id of the column to resolve the index whenever a cell value is needed to ensure the correct data is always retrived for the correct column without needing to keep track of column indexes. Change-Id: I8dc6fd4bb9f1cf917d7a6beea30a4a0230eea074 --- .../com/vaadin/client/ui/grid/GridConnector.java | 21 ++++++++++++++++----- .../components/grid/GridBasicFeaturesTest.java | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index e55a71cb2e..8100cd875a 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -51,15 +51,26 @@ public class GridConnector extends AbstractComponentConnector { */ private class CustomGridColumn extends GridColumn { - private final int columnIndex; + private final String id; - public CustomGridColumn(int columnIndex) { - this.columnIndex = columnIndex; + public CustomGridColumn(String id) { + this.id = id; } @Override public String getValue(String[] obj) { - return obj[columnIndex]; + return obj[resolveCurrentIndexFromState()]; + } + + private int resolveCurrentIndexFromState() { + List columns = getState().columns; + int numColumns = columns.size(); + for (int index = 0; index < numColumns; index++) { + if (columns.get(index).id.equals(id)) { + return index; + } + } + return -1; } } @@ -203,7 +214,7 @@ public class GridConnector extends AbstractComponentConnector { */ private void addColumnFromStateChangeEvent(int columnIndex) { GridColumnState state = getState().columns.get(columnIndex); - CustomGridColumn column = new CustomGridColumn(columnIndex); + CustomGridColumn column = new CustomGridColumn(state.id); columnIdToColumn.put(state.id, column); // Adds a column to grid, and registers Grid with the column. diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index 7163fbea75..73bef67c32 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -15,6 +15,8 @@ */ package com.vaadin.tests.components.grid; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -166,6 +168,25 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { assertEquals("Column1", cells.get(0).getText()); } + @Test + public void testDataLoadingAfterRowRemoval() throws Exception { + openTestURL(); + + // Remove columns 2,3,4 + selectMenuPath("Component", "Columns", "Column2", "Remove"); + selectMenuPath("Component", "Columns", "Column3", "Remove"); + selectMenuPath("Component", "Columns", "Column4", "Remove"); + + // Scroll so new data is lazy loaded + scrollGridVerticallyTo(1000); + + // Let lazy loading do its job + sleep(1000); + + // Check that row is loaded + assertThat(getBodyCellByRowAndColumn(11, 1).getText(), not("...")); + } + @Test public void testFreezingColumn() throws Exception { openTestURL(); -- cgit v1.2.3 From d91b0b1417f9731a1e8dc2acc93f610a2581543c Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 20 May 2014 13:04:53 +0300 Subject: Remove unnecessary javadoc and add TestCategory annotation to Grid tests Change-Id: Ibc8da060e5592dfa6af7e1fc9af83dea7119b387 --- .../com/vaadin/tests/server/component/grid/GridColumnGroups.java | 5 ----- uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java | 4 ---- .../src/com/vaadin/tests/components/grid/BasicEscalatorTest.java | 2 ++ uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java | 4 ++-- .../com/vaadin/tests/components/grid/GridBasicFeaturesTest.java | 7 ++----- uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java | 5 ----- uitest/src/com/vaadin/tests/components/grid/GridScrolling.java | 3 --- .../src/com/vaadin/tests/components/grid/GridSingleColumnTest.java | 2 ++ 8 files changed, 8 insertions(+), 24 deletions(-) (limited to 'uitest/src') diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java index 4350bf1a7b..3cc1c5f0d7 100644 --- a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java +++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java @@ -35,11 +35,6 @@ import com.vaadin.ui.components.grid.ColumnGroup; import com.vaadin.ui.components.grid.ColumnGroupRow; import com.vaadin.ui.components.grid.Grid; -/** - * - * @since - * @author Vaadin Ltd - */ public class GridColumnGroups { private Grid grid; diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java index 61d263f433..79e1da3786 100644 --- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java +++ b/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java @@ -30,10 +30,6 @@ import com.vaadin.ui.Layout; import com.vaadin.ui.NativeSelect; import com.vaadin.ui.TextField; -/** - * @since 7.2 - * @author Vaadin Ltd - */ @Widgetset(TestingWidgetSet.NAME) public class BasicEscalator extends AbstractTestUI { public static final String ESCALATOR = "escalator"; diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java index bd1a580c73..3cb4d83063 100644 --- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java @@ -26,8 +26,10 @@ import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import com.vaadin.tests.annotations.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; +@TestCategory("grid") public class BasicEscalatorTest extends MultiBrowserTest { @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index 0faabff88a..9aafaa4f1b 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -31,7 +31,7 @@ import com.vaadin.ui.components.grid.GridColumn; /** * Tests the basic features like columns, footers and headers * - * @since 7.2 + * @since 7.4 * @author Vaadin Ltd */ public class GridBasicFeatures extends AbstractComponentTest { @@ -334,7 +334,7 @@ public class GridBasicFeatures extends AbstractComponentTest { }, null); } - @SuppressWarnings("boxing") + @SuppressWarnings("boxing") protected void addHeightByRowActions() { createCategory("Height by Rows", "Size"); diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index 73bef67c32..0f4a899750 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -30,13 +30,10 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import com.vaadin.tests.annotations.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; -/** - * - * @since - * @author Vaadin Ltd - */ +@TestCategory("grid") public class GridBasicFeaturesTest extends MultiBrowserTest { @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java b/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java index 66e7651f76..423e521939 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java @@ -27,11 +27,6 @@ import com.vaadin.ui.components.grid.ColumnGroupRow; import com.vaadin.ui.components.grid.Grid; import com.vaadin.ui.components.grid.GridColumn; -/** - * - * @since - * @author Vaadin Ltd - */ public class GridColumnGroups extends AbstractTestUI { private final int COLUMNS = 4; diff --git a/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java b/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java index d514fbd0c5..bf46851fe0 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java @@ -27,9 +27,6 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.components.grid.Grid; -/** - * - */ @SuppressWarnings("serial") public class GridScrolling extends AbstractTestUI { diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java index 9c1ec88df7..8e81ed3e05 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java @@ -22,8 +22,10 @@ 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 { @Test -- cgit v1.2.3 From a8308bcfe0fae96c231f91db4f03533bea71a5db Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 20 May 2014 17:24:12 +0300 Subject: Update license headers in tests Change-Id: I896a6ed911000ae7d952757964117f5d28d0c27b --- .../src/com/vaadin/tests/server/component/grid/GridColumnGroups.java | 2 +- .../tests/src/com/vaadin/tests/server/component/grid/GridColumns.java | 2 +- uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java | 2 +- uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java | 2 +- uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java | 2 +- uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java | 2 +- uitest/src/com/vaadin/tests/components/grid/GridScrolling.java | 2 +- uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java | 2 +- uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) (limited to 'uitest/src') diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java index 3cc1c5f0d7..21bfbbb37e 100644 --- a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java +++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 Vaadin Ltd. + * 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 diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java index da07611b48..381135d7ab 100644 --- a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java +++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 Vaadin Ltd. + * 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 diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java index 79e1da3786..c2e73cc72c 100644 --- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java +++ b/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 Vaadin Ltd. + * 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 diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java index 3cb4d83063..5658954e06 100644 --- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 Vaadin Ltd. + * 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 diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index 9aafaa4f1b..9fb962c495 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 Vaadin Ltd. + * 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 diff --git a/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java b/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java index 423e521939..f1199301d9 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 Vaadin Ltd. + * 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 diff --git a/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java b/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java index bf46851fe0..e8b327639b 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 Vaadin Ltd. + * 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 diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java index 08b4f0c0d7..56fe904093 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 Vaadin Ltd. + * 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 diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java index 8e81ed3e05..10d2c8592a 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 Vaadin Ltd. + * 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 -- cgit v1.2.3 From 4508ab4592791f7c045623173298e950681b1c5c Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 20 May 2014 17:25:39 +0300 Subject: Add a dummy GridElement and use it in GridBasicFeaturesTest (#13334) Change-Id: I729d906a14da66f5a4827ccbaa48762d69ebbe11 --- .../components/grid/GridBasicFeaturesTest.java | 36 +++++++--------------- .../vaadin/tests/components/grid/GridElement.java | 30 ++++++++++++++++++ 2 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridElement.java (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index 0f4a899750..ac1951242c 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 Vaadin Ltd. + * 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 @@ -25,7 +25,6 @@ import java.util.List; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; @@ -269,13 +268,13 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { final By newRow = By.xpath("//td[text()='newcell: 0']"); - assertTrue("Unexpected initial state", !elementIsFound(newRow)); + assertTrue("Unexpected initial state", !isElementPresent(newRow)); selectMenuPath("Component", "Body rows", "Add first row"); - assertTrue("Add row failed", elementIsFound(newRow)); + assertTrue("Add row failed", isElementPresent(newRow)); selectMenuPath("Component", "Body rows", "Remove first row"); - assertTrue("Remove row failed", !elementIsFound(newRow)); + assertTrue("Remove row failed", !isElementPresent(newRow)); } /** @@ -300,14 +299,6 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { "modified: Column0", getBodyCellByRowAndColumn(1, 1).getText()); } - private boolean elementIsFound(By locator) { - try { - return driver.findElement(locator) != null; - } catch (NoSuchElementException e) { - return false; - } - } - private void assertPrimaryStylename(String stylename) { assertTrue(getGridElement().getAttribute("class").contains(stylename)); @@ -348,32 +339,27 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { } private WebElement getVerticalScroller() { - return getDriver().findElement( - By.xpath("//div[@id='testComponent']/div[1]")); + return getGridElement().findElement(By.xpath("./div[1]")); } private WebElement getHorizontalScroller() { - return getDriver().findElement( - By.xpath("//div[@id='testComponent']/div[2]")); + return getGridElement().findElement(By.xpath("./div[2]")); } private WebElement getTableWrapper() { - return getDriver().findElement( - By.xpath("//div[@id='testComponent']/div[3]")); + return getGridElement().findElement(By.xpath("./div[3]")); } - private WebElement getGridElement() { - return getDriver().findElement(By.id("testComponent")); + private GridElement getGridElement() { + return $(GridElement.class).id("testComponent"); } private List getGridHeaderRowCells() { - return getDriver().findElements( - By.xpath("//div[@id='testComponent']//thead//th")); + return getGridElement().findElements(By.xpath(".//thead//th")); } private List getGridFooterRowCells() { - return getDriver().findElements( - By.xpath("//div[@id='testComponent']//tfoot//td")); + return getGridElement().findElements(By.xpath(".//tfoot//td")); } private void scrollGridVerticallyTo(double px) { 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..51e07f6bb1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridElement.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.components.grid; + +import com.vaadin.testbench.elements.AbstractComponentElement; +import com.vaadin.testbench.elements.ServerClass; + +/** + * TestBench Element API for Grid + * + * @since 7.4 + * @author Vaadin Ltd + */ +@ServerClass("com.vaadin.ui.components.grid.Grid") +public class GridElement extends AbstractComponentElement { + +} -- cgit v1.2.3 From 0eb12c4c82ceca35f7e73ca285f49bb72251de88 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Fri, 23 May 2014 14:24:47 +0300 Subject: Refactored client Renderers once again #13334 The following things are refactored in this changeset: * Cell interface removed * CellInfo -> Cell * Renderer interface becomes a single method interface * All other methods moved from Renderer to new ComplexRenderer interface Change-Id: I567868b8dc73783988bce6c11bc23e12d5479172 --- client/src/com/vaadin/client/ui/grid/Cell.java | 79 +++++++------ client/src/com/vaadin/client/ui/grid/CellInfo.java | 82 -------------- .../vaadin/client/ui/grid/EscalatorUpdater.java | 4 +- .../com/vaadin/client/ui/grid/FlyweightCell.java | 44 +++++--- .../com/vaadin/client/ui/grid/FlyweightRow.java | 8 +- client/src/com/vaadin/client/ui/grid/Grid.java | 15 +-- client/src/com/vaadin/client/ui/grid/Renderer.java | 52 +-------- .../client/ui/grid/renderers/AbstractRenderer.java | 51 --------- .../client/ui/grid/renderers/ComplexRenderer.java | 123 +++++++++++++++++++++ .../client/ui/grid/renderers/DateRenderer.java | 7 +- .../client/ui/grid/renderers/HtmlRenderer.java | 7 +- .../client/ui/grid/renderers/NumberRenderer.java | 7 +- .../client/ui/grid/renderers/TextRenderer.java | 7 +- .../tests/widgetset/client/grid/VTestGrid.java | 16 +-- 14 files changed, 235 insertions(+), 267 deletions(-) delete mode 100644 client/src/com/vaadin/client/ui/grid/CellInfo.java delete mode 100644 client/src/com/vaadin/client/ui/grid/renderers/AbstractRenderer.java create mode 100644 client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Cell.java b/client/src/com/vaadin/client/ui/grid/Cell.java index c4e1471da4..33495ebf87 100644 --- a/client/src/com/vaadin/client/ui/grid/Cell.java +++ b/client/src/com/vaadin/client/ui/grid/Cell.java @@ -13,63 +13,70 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.vaadin.client.ui.grid; import com.google.gwt.dom.client.Element; -import com.google.gwt.user.client.ui.HasOneWidget; /** - * A representation of a single cell. - *

- * A Cell instance will be provided to the {@link EscalatorUpdater} responsible - * for rendering the cells in a certain {@link RowContainer}. + * Describes a cell + * + * TODO The description is still very vague since the content and naming of this + * class is still under debate and the API is not final. Improve the description + * when API has been finalized. * - * @since 7.4 * @author Vaadin Ltd */ -public interface Cell extends HasOneWidget { +public class Cell { + + private final int row; + + private final int column; + + private final Element element; /** - * Gets the index of the row this cell is in. + * Constructs a new {@link Cell} * - * @return the index of the row this cell is in + * @param row + * The index of the row + * @param column + * The index of the column + * @param element + * The cell element */ - public int getRow(); + public Cell(int row, int column, Element element) { + super(); + this.row = row; + this.column = column; + this.element = element; + } /** - * Gets the index of the column this cell is in. + * Returns the index of the row the cell resides on + * + * @return the row index * - * @return the index of the column this cell is in */ - public int getColumn(); + public int getRow() { + return row; + } /** - * Gets the root element for this cell. The {@link EscalatorUpdater} may - * update the class names of the element, add inline styles and freely - * modify the contents. - *

- * Avoid modifying the dimensions, positioning or colspan of the cell - * element. + * Returns the index of the column the cell resides on * - * @return The root element for this cell. Never null. + * @return the column index */ - public Element getElement(); + public int getColumn() { + return column; + } /** - * Sets the column span of the cell. - *

- * This will overwrite any possible "colspan" attribute in the current - * element (i.e. the object returned by {@link #getElement()}). This will - * also handle internal bookkeeping, skip the rendering of any affected - * adjacent cells, and make sure that the current cell's dimensions are - * handled correctly. + * Returns the element of the cell * - * @param numberOfCells - * the number of cells to span to the right, or 1 to - * unset any column spans - * @throws IllegalArgumentException - * if numberOfCells < 1 + * @return the element */ - public void setColSpan(int numberOfCells) throws IllegalArgumentException; -} \ No newline at end of file + public Element getElement() { + return element; + } + +} diff --git a/client/src/com/vaadin/client/ui/grid/CellInfo.java b/client/src/com/vaadin/client/ui/grid/CellInfo.java deleted file mode 100644 index 2f3dae8c4d..0000000000 --- a/client/src/com/vaadin/client/ui/grid/CellInfo.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid; - -import com.google.gwt.dom.client.Element; - -/** - * Describes a cell - * - * TODO The description is still very vague since the content and naming of this - * class is still under debate and the API is not final. Improve the description - * when API has been finalized. - * - * @author Vaadin Ltd - */ -public class CellInfo { - - private final int row; - - private final int column; - - private final Element element; - - /** - * Constructs a new {@link CellInfo} - * - * @param row - * The index of the row - * @param column - * The index of the column - * @param element - * The cell element - */ - public CellInfo(int row, int column, Element element) { - super(); - this.row = row; - this.column = column; - this.element = element; - } - - /** - * Returns the index of the row the cell resides on - * - * @return the row index - * - */ - public int getRow() { - return row; - } - - /** - * Returns the index of the column the cell resides on - * - * @return the column index - */ - public int getColumn() { - return column; - } - - /** - * Returns the element of the cell - * - * @return the element - */ - public Element getElement() { - return element; - } - -} diff --git a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java index c856d5f027..c6fe90850a 100644 --- a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java +++ b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java @@ -36,7 +36,7 @@ public interface EscalatorUpdater { public static final EscalatorUpdater NULL = new EscalatorUpdater() { @Override public void updateCells(final Row row, - final Iterable cellsToUpdate) { + final Iterable cellsToUpdate) { // NOOP } }; @@ -61,5 +61,5 @@ public interface EscalatorUpdater { * You should neither store nor reuse the reference to the list, * nor to the individual cells */ - public void updateCells(Row row, Iterable cellsToUpdate); + public void updateCells(Row row, Iterable cellsToUpdate); } diff --git a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java index 16ee265611..950b3e167a 100644 --- a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java +++ b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java @@ -25,18 +25,19 @@ import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.grid.FlyweightRow.CellIterator; /** - * An internal implementation of the {@link Cell} interface. + * A {@link FlyweightCell} represents a cell in the {@link Grid} or + * {@link Escalator} at a certain point in time. + * *

- * These instances are populated into a {@link FlyweightRow} instance, and - * intended to be reused when rendering cells in an escalator. + * Since the {@link FlyweightCell} follows the Flyweight-pattern + * any instance of this object is subject to change without the user knowing it + * and so should not be stored anywhere outside of the method providing these + * instances. * * @since 7.4 * @author Vaadin Ltd - * @see FlyweightRow#getCells() - * @see FlyweightRow#addCells(int, int) - * @see FlyweightRow#removeCells(int, int) */ -class FlyweightCell implements Cell { +public class FlyweightCell { static final String COLSPAN_ATTR = "colSpan"; private final int column; @@ -53,19 +54,26 @@ class FlyweightCell implements Cell { this.escalator = escalator; } - @Override + /** + * Returns the row index of the cell + */ public int getRow() { assertSetup(); return row.getRow(); } - @Override + /** + * Returns the column index of the cell + */ public int getColumn() { assertSetup(); return column; } - @Override + /** + * Returns the element of the cell. Can be either a TD element + * or a TH element. + */ public Element getElement() { return (Element) row.getElement().getChild(column); } @@ -109,7 +117,6 @@ class FlyweightCell implements Cell { + "inappropriately."; } - @Override public void setColSpan(final int numberOfCells) { /*- * This will default to 1 if unset, as per DOM specifications: @@ -157,12 +164,18 @@ class FlyweightCell implements Cell { } } - @Override + /** + * @deprecated Will be removed in further refactorings + */ + @Deprecated public Widget getWidget() { return Escalator.getWidgetFromCell(getElement()); } - @Override + /** + * @deprecated Will be removed in further refactorings + */ + @Deprecated public void setWidget(Widget widget) { Widget oldWidget = getWidget(); @@ -197,7 +210,10 @@ class FlyweightCell implements Cell { } } - @Override + /** + * @deprecated Will be removed in further refactorings + */ + @Deprecated public void setWidget(IsWidget w) { setWidget(Widget.asWidgetOrNull(w)); } diff --git a/client/src/com/vaadin/client/ui/grid/FlyweightRow.java b/client/src/com/vaadin/client/ui/grid/FlyweightRow.java index 8bb9a54321..3505b317d1 100644 --- a/client/src/com/vaadin/client/ui/grid/FlyweightRow.java +++ b/client/src/com/vaadin/client/ui/grid/FlyweightRow.java @@ -35,7 +35,7 @@ import com.google.gwt.dom.client.Node; */ class FlyweightRow implements Row { - static class CellIterator implements Iterator { + static class CellIterator implements Iterator { /** A defensive copy of the cells in the current row. */ private final ArrayList cells; private int cursor = 0; @@ -188,11 +188,11 @@ class FlyweightRow implements Row { * @see #setup(Element, int, int[]) * @see #teardown() */ - Iterable getCells() { + Iterable getCells() { assertSetup(); - return new Iterable() { + return new Iterable() { @Override - public Iterator iterator() { + public Iterator iterator() { return new CellIterator(cells); } }; diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index b81fc3c673..d1e299ba5a 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -510,7 +510,7 @@ public class Grid extends Composite { public abstract Renderer getGroupRenderer(ColumnGroup group); @Override - public void updateCells(Row row, Iterable cellsToUpdate) { + public void updateCells(Row row, Iterable cellsToUpdate) { int rowIndex; if (inverted) { @@ -521,7 +521,7 @@ public class Grid extends Composite { if (firstRowIsVisible() && rowIndex == 0) { // column headers - for (Cell cell : cellsToUpdate) { + for (FlyweightCell cell : cellsToUpdate) { GridColumn column = getColumnFromVisibleIndex(cell .getColumn()); if (column != null) { @@ -551,7 +551,7 @@ public class Grid extends Composite { assert groupRow != null; - for (Cell cell : cellsToUpdate) { + for (FlyweightCell cell : cellsToUpdate) { GridColumn column = getColumnFromVisibleIndex(cell .getColumn()); ColumnGroup group = getGroupForColumn(groupRow, column); @@ -653,7 +653,8 @@ public class Grid extends Composite { return new EscalatorUpdater() { @Override - public void updateCells(Row row, Iterable cellsToUpdate) { + public void updateCells(Row row, + Iterable cellsToUpdate) { int rowIndex = row.getRow(); if (dataSource == null) { setCellsLoading(cellsToUpdate); @@ -666,7 +667,7 @@ public class Grid extends Composite { return; } - for (Cell cell : cellsToUpdate) { + for (FlyweightCell cell : cellsToUpdate) { GridColumn column = getColumnFromVisibleIndex(cell .getColumn()); if (column != null) { @@ -676,8 +677,8 @@ public class Grid extends Composite { } } - private void setCellsLoading(Iterable cellsToUpdate) { - for (Cell cell : cellsToUpdate) { + private void setCellsLoading(Iterable cellsToUpdate) { + for (FlyweightCell cell : cellsToUpdate) { cell.getElement().setInnerText("..."); } } diff --git a/client/src/com/vaadin/client/ui/grid/Renderer.java b/client/src/com/vaadin/client/ui/grid/Renderer.java index b96b89b730..e312a9da20 100644 --- a/client/src/com/vaadin/client/ui/grid/Renderer.java +++ b/client/src/com/vaadin/client/ui/grid/Renderer.java @@ -15,9 +15,6 @@ */ package com.vaadin.client.ui.grid; -import java.util.Collection; - -import com.google.gwt.dom.client.NativeEvent; /** * Renderer for rending a value <T> into cell. @@ -34,44 +31,6 @@ import com.google.gwt.dom.client.NativeEvent; */ public interface Renderer { - /** - * Called at initialization stage. Perform any initialization here e.g. - * attach handlers, attach widgets etc. - * - * @param cell - * The cell. Note that the cell is a flyweight and should not be - * stored outside of the method as it will change. - */ - void init(Cell cell); - - /** - * Returns the events that the renderer should consume. These are also the - * events that the Grid will pass to - * {@link #onBrowserEvent(CellInfo, NativeEvent)} when they occur. - * null if no events are consumed - * - * @return the consumed events, or null if no events are consumed - * - * @see com.google.gwt.dom.client.BrowserEvents - */ - Collection getConsumedEvents(); - - /** - * Called whenever a registered event is triggered in the column the - * renderer renders. - *

- * The events that triggers this needs to be returned by the - * {@link #getConsumedEvents()} method. - * - * @param cellInfo - * Object containing information about the cell the event was - * triggered on. - * - * @param event - * The original DOM event - */ - void onBrowserEvent(CellInfo cell, NativeEvent event); - /** * Called whenever the {@link Grid} updates a cell * @@ -82,14 +41,5 @@ public interface Renderer { * @param data * The column data object */ - void render(Cell cell, T data); - - /** - * Called when the cell is "activated" by pressing enter or - * double clicking - * - * @return true if event was handled and should not be - * interpreted as a generic gesture by Grid. - */ - boolean onActivate(); + void render(FlyweightCell cell, T data); } diff --git a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRenderer.java deleted file mode 100644 index 91f3b27eef..0000000000 --- a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRenderer.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.renderers; - -import java.util.Collection; - -import com.google.gwt.dom.client.NativeEvent; -import com.vaadin.client.ui.grid.Cell; -import com.vaadin.client.ui.grid.CellInfo; -import com.vaadin.client.ui.grid.Renderer; - -/** - * Abstract base class for renderers. - * - * @author Vaadin Ltd - */ -public abstract class AbstractRenderer implements Renderer { - - @Override - public void init(Cell cell) { - // Implement if needed - } - - @Override - public Collection getConsumedEvents() { - return null; - } - - @Override - public void onBrowserEvent(CellInfo cell, NativeEvent event) { - // Implement if needed - } - - @Override - public boolean onActivate() { - return false; - } -} diff --git a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java new file mode 100644 index 0000000000..cf3e43c88a --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java @@ -0,0 +1,123 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.renderers; + +import java.util.Collection; + +import com.google.gwt.dom.client.NativeEvent; +import com.vaadin.client.ui.grid.Cell; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Renderer; + +/** + * Base class for renderers that needs initialization and destruction logic + * (override {@link #init(FlyweightCell) and #destroy(FlyweightCell) } and event + * handling (see {@link #onBrowserEvent(Cell, NativeEvent)}, + * {@link #getConsumedEvents()} and {@link #onActivate()}. + * + *

+ * Also provides a helper method for hiding the cell contents by overriding + * {@link #setContentVisible(FlyweightCell, boolean)} + * + * @since 7.4 + * @author Vaadin Ltd + */ +public abstract class ComplexRenderer implements Renderer { + + /** + * Called at initialization stage. Perform any initialization here e.g. + * attach handlers, attach widgets etc. + * + * @param cell + * The cell. Note that the cell is not to be stored outside of + * the method as the cell install will change. See + * {@link FlyweightCell} + */ + public void init(FlyweightCell cell) { + // Implement if needed + } + + /** + * Called after the cell is deemed to be destroyed and no longer used by the + * Grid. Called after the cell element is detached from the DOM. + * + * @param cell + * The cell. Note that the cell is not to be stored outside of + * the method as the cell install will change. See + * {@link FlyweightCell} + */ + public void destroy(FlyweightCell cell) { + // Implement if needed + } + + /** + * Returns the events that the renderer should consume. These are also the + * events that the Grid will pass to + * {@link #onBrowserEvent(Cell, NativeEvent)} when they occur. + * null if no events are consumed + * + * @return the consumed events, or null if no events are consumed + * + * @see com.google.gwt.dom.client.BrowserEvents + */ + public Collection getConsumedEvents() { + return null; + } + + /** + * Called whenever a registered event is triggered in the column the + * renderer renders. + *

+ * The events that triggers this needs to be returned by the + * {@link #getConsumedEvents()} method. + * + * @param cell + * Object containing information about the cell the event was + * triggered on. + * + * @param event + * The original DOM event + */ + public void onBrowserEvent(Cell cell, NativeEvent event) { + // Implement if needed + } + + /** + * Hides content by setting visibility: hidden to all elements inside the + * cell. Text nodes are left as is for now - renderers that add such to the + * root element need to implement explicit support hiding them + * + * @param cell + * The cell + * @param visible + * Is the cell content be visible + * @return true if the content should be set visible + */ + public boolean setContentVisible(FlyweightCell cell, boolean visible) { + return false; + } + + /** + * Called when the cell is "activated" by pressing enter, + * double clicking or performing a double tap on the cell. + * + * @return true if event was handled and should not be + * interpreted as a generic gesture by Grid. + */ + public boolean onActivate() { + return false; + } +} diff --git a/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java index 59f56eafc4..d52e97c62c 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java @@ -19,7 +19,8 @@ import java.util.Date; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.i18n.client.TimeZone; -import com.vaadin.client.ui.grid.Cell; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Renderer; /** * A renderer for rendering dates into cells @@ -27,7 +28,7 @@ import com.vaadin.client.ui.grid.Cell; * @since 7.4 * @author Vaadin Ltd */ -public class DateRenderer extends AbstractRenderer { +public class DateRenderer implements Renderer { private DateTimeFormat format = DateTimeFormat.getShortDateTimeFormat(); @@ -35,7 +36,7 @@ public class DateRenderer extends AbstractRenderer { .getTimezoneOffset()); @Override - public void render(Cell cell, Date date) { + public void render(FlyweightCell cell, Date date) { String dateStr = format.format(date, timeZone); cell.getElement().setInnerText(dateStr); } diff --git a/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java index 0c33f46cd8..6cb9603d3c 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java @@ -17,7 +17,8 @@ package com.vaadin.client.ui.grid.renderers; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlUtils; -import com.vaadin.client.ui.grid.Cell; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Renderer; /** * Renders a string as HTML into a cell. @@ -31,10 +32,10 @@ import com.vaadin.client.ui.grid.Cell; * @author Vaadin Ltd * @see SafeHtmlUtils#fromSafeConstant(String) */ -public class HtmlRenderer extends AbstractRenderer { +public class HtmlRenderer implements Renderer { @Override - public void render(Cell cell, String htmlString) { + public void render(FlyweightCell cell, String htmlString) { cell.getElement().setInnerSafeHtml( SafeHtmlUtils.fromSafeConstant(htmlString)); } diff --git a/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java index a21f0d776a..b1bf7083a5 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java @@ -16,7 +16,8 @@ package com.vaadin.client.ui.grid.renderers; import com.google.gwt.i18n.client.NumberFormat; -import com.vaadin.client.ui.grid.Cell; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Renderer; /** * Renders a number into a cell using a specific {@link NumberFormat}. By @@ -28,7 +29,7 @@ import com.vaadin.client.ui.grid.Cell; * @param * The number type to render. */ -public class NumberRenderer extends AbstractRenderer { +public class NumberRenderer implements Renderer { private NumberFormat format = NumberFormat.getDecimalFormat(); @@ -57,7 +58,7 @@ public class NumberRenderer extends AbstractRenderer { } @Override - public void render(Cell cell, Number number) { + public void render(FlyweightCell cell, Number number) { cell.getElement().setInnerText(format.format(number)); } } diff --git a/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java index a60ad705d6..36ffbae22d 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java @@ -15,7 +15,8 @@ */ package com.vaadin.client.ui.grid.renderers; -import com.vaadin.client.ui.grid.Cell; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Renderer; /** * Renderer that renders text into a cell. @@ -23,10 +24,10 @@ import com.vaadin.client.ui.grid.Cell; * @since 7.4 * @author Vaadin Ltd */ -public class TextRenderer extends AbstractRenderer { +public class TextRenderer implements Renderer { @Override - public void render(Cell cell, String text) { + public void render(FlyweightCell cell, String text) { cell.getElement().setInnerText(text); } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java index bdbff4a6f0..dcbe367bb2 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java @@ -5,10 +5,10 @@ import java.util.List; import com.google.gwt.user.client.Window.Location; import com.google.gwt.user.client.ui.Composite; -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.FlyweightCell; import com.vaadin.client.ui.grid.Row; import com.vaadin.client.ui.grid.RowContainer; import com.vaadin.shared.ui.grid.ScrollDestination; @@ -43,8 +43,8 @@ public class VTestGrid extends Composite { return new EscalatorUpdater() { @Override public void updateCells(final Row row, - final Iterable cellsToUpdate) { - for (final Cell cell : cellsToUpdate) { + final Iterable cellsToUpdate) { + for (final FlyweightCell cell : cellsToUpdate) { if (cell.getColumn() % 3 == 0) { cell.setColSpan(2); } @@ -61,8 +61,8 @@ public class VTestGrid extends Composite { return new EscalatorUpdater() { @Override public void updateCells(final Row row, - final Iterable cellsToUpdate) { - for (final Cell cell : cellsToUpdate) { + final Iterable cellsToUpdate) { + for (final FlyweightCell cell : cellsToUpdate) { if (cell.getColumn() % 3 == 1) { cell.setColSpan(2); } @@ -79,7 +79,7 @@ public class VTestGrid extends Composite { return new EscalatorUpdater() { private int i = 0; - public void renderCell(final Cell cell) { + public void renderCell(final FlyweightCell cell) { final Integer columnName = columns.get(cell.getColumn()); final Integer rowName = rows.get(cell.getRow()); String cellInfo = columnName + "," + rowName; @@ -123,8 +123,8 @@ public class VTestGrid extends Composite { @Override public void updateCells(final Row row, - final Iterable cellsToUpdate) { - for (final Cell cell : cellsToUpdate) { + final Iterable cellsToUpdate) { + for (final FlyweightCell cell : cellsToUpdate) { renderCell(cell); } } -- cgit v1.2.3 From 61b04537b350c39f06310b55089f259f2bdab3d8 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Wed, 5 Mar 2014 09:35:48 +0200 Subject: Sort DOM elements for better WAI-ARIA support (#13334) Change-Id: I3fe6b2a8ad2b72b91db61135bd6505dcfa53034d --- .../src/com/vaadin/client/ui/grid/Escalator.java | 180 ++++++++++++++++++++- .../tests/components/grid/BasicEscalator.java | 13 +- .../tests/components/grid/BasicEscalatorTest.java | 167 +++++++++++++++++-- 3 files changed, 342 insertions(+), 18 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index edffbb0430..2f1535ccd4 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -191,14 +191,16 @@ abstract class JsniWorkaround { */ protected JavaScriptObject touchEndFunction; + protected TouchHandlerBundle touchHandlerBundle; + protected JsniWorkaround(final Escalator escalator) { scrollListenerFunction = createScrollListenerFunction(escalator); mousewheelListenerFunction = createMousewheelListenerFunction(escalator); - final TouchHandlerBundle bundle = new TouchHandlerBundle(escalator); - touchStartFunction = bundle.getTouchStartHandler(); - touchMoveFunction = bundle.getTouchMoveHandler(); - touchEndFunction = bundle.getTouchEndHandler(); + touchHandlerBundle = new TouchHandlerBundle(escalator); + touchStartFunction = touchHandlerBundle.getTouchStartHandler(); + touchMoveFunction = touchHandlerBundle.getTouchMoveHandler(); + touchEndFunction = touchHandlerBundle.getTouchEndHandler(); } /** @@ -431,6 +433,12 @@ public class Escalator extends Widget { animationHandle = AnimationScheduler.get() .requestAnimationFrame(mover, escalator.bodyElem); event.getNativeEvent().preventDefault(); + + /* + * this initializes a correct timestamp, and also renders the + * first frame for added responsiveness. + */ + mover.execute(Duration.currentTimeMillis()); } public void touchEnd(@SuppressWarnings("unused") @@ -440,6 +448,7 @@ public class Escalator extends Widget { if (touches == 0) { escalator.scroller.handleFlickScroll(deltaX, deltaY, lastTime); + escalator.body.domSorter.reschedule(); } } } @@ -1902,6 +1911,8 @@ public class Escalator extends Widget { * The order in which row elements are rendered visually in the browser, * with the help of CSS tricks. Usually has nothing to do with the DOM * order. + * + * @see #sortDomElements() */ private final LinkedList visualRowOrder = new LinkedList(); @@ -1939,6 +1950,60 @@ public class Escalator extends Widget { setTopRowLogicalIndex(topRowLogicalIndex + diff); } + private class DeferredDomSorter { + private static final int SORT_DELAY_MILLIS = 50; + + // as it happens, 3 frames = 50ms @ 60fps. + private static final int REQUIRED_FRAMES_PASSED = 3; + + private final AnimationCallback frameCounter = new AnimationCallback() { + @Override + public void execute(double timestamp) { + framesPassed++; + boolean domWasSorted = sortIfConditionsMet(); + if (!domWasSorted) { + animationHandle = AnimationScheduler.get() + .requestAnimationFrame(this); + } + } + }; + + private int framesPassed; + private double startTime; + private AnimationHandle animationHandle; + + public void reschedule() { + resetConditions(); + animationHandle = AnimationScheduler.get() + .requestAnimationFrame(frameCounter); + } + + private boolean sortIfConditionsMet() { + boolean enoughFramesHavePassed = framesPassed >= REQUIRED_FRAMES_PASSED; + boolean enoughTimeHasPassed = (Duration.currentTimeMillis() - startTime) >= SORT_DELAY_MILLIS; + boolean conditionsMet = enoughFramesHavePassed + && enoughTimeHasPassed; + + if (conditionsMet) { + resetConditions(); + sortDomElements(); + } + + return conditionsMet; + } + + private void resetConditions() { + if (animationHandle != null) { + animationHandle.cancel(); + animationHandle = null; + } + startTime = Duration.currentTimeMillis(); + framesPassed = 0; + } + } + + private DeferredDomSorter domSorter = new DeferredDomSorter(); + public BodyRowContainer(final Element bodyElement) { super(bodyElement); } @@ -2086,6 +2151,15 @@ public class Escalator extends Widget { if (rowsWereMoved) { fireRowVisibilityChangeEvent(); + + if (scroller.touchHandlerBundle.touches == 0) { + /* + * this will never be called on touch scrolling. That is + * handled separately and explicitly by + * TouchHandlerBundle.touchEnd(); + */ + domSorter.reschedule(); + } } } @@ -2187,6 +2261,7 @@ public class Escalator extends Widget { } fireRowVisibilityChangeEvent(); + sortDomElements(); } return addedRows; } @@ -2733,6 +2808,9 @@ public class Escalator extends Widget { logicalTargetIndex); } } + + fireRowVisibilityChangeEvent(); + sortDomElements(); } updateTopRowLogicalIndex(-removedAbove.length()); @@ -2742,8 +2820,6 @@ public class Escalator extends Widget { * or it won't work correctly (due to setScrollTop invocation) */ scroller.recalculateScrollbarsForVirtualViewport(); - - fireRowVisibilityChangeEvent(); } private void paintRemoveRowsAtMiddle(final Range removedLogicalInside, @@ -3160,6 +3236,98 @@ public class Escalator extends Widget { Profiler.leave("Escalator.BodyRowContainer.reapplyDefaultRowHeights"); } + + /** + * Sorts the rows in the DOM to correspond to the visual order. + * + * @see #visualRowOrder + */ + private void sortDomElements() { + final String profilingName = "Escalator.BodyRowContainer.sortDomElements"; + Profiler.enter(profilingName); + + /* + * Focus is lost from an element if that DOM element is (or any of + * its parents are) removed from the document. Therefore, we sort + * everything around that row instead. + */ + final Element activeRow = getEscalatorRowWithFocus(); + + if (activeRow != null) { + assert activeRow.getParentElement() == root : "Trying to sort around a row that doesn't exist in body"; + assert visualRowOrder.contains(activeRow) : "Trying to sort around a row that doesn't exist in visualRowOrder."; + } + + /* + * Two cases handled simultaneously: + * + * 1) No focus on rows. We iterate visualRowOrder backwards, and + * take the respective element in the DOM, and place it as the first + * child in the body element. Then we take the next-to-last from + * visualRowOrder, and put that first, pushing the previous row as + * the second child. And so on... + * + * 2) Focus on some row within Escalator body. Again, we iterate + * visualRowOrder backwards. This time, we use the focused row as a + * pivot: Instead of placing rows from the bottom of visualRowOrder + * and placing it first, we place it underneath the focused row. + * Once we hit the focused row, we don't move it (to not reset + * focus) but change sorting mode. After that, we place all rows as + * the first child. + */ + + /* + * If we have a focused row, start in the mode where we put + * everything underneath that row. Otherwise, all rows are placed as + * first child. + */ + boolean insertFirst = (activeRow == null); + + final ListIterator i = visualRowOrder + .listIterator(visualRowOrder.size()); + while (i.hasPrevious()) { + Element tr = i.previous(); + + if (tr == activeRow) { + insertFirst = true; + } else if (insertFirst) { + root.insertFirst(tr); + } else { + root.insertAfter(tr, activeRow); + } + } + + Profiler.leave(profilingName); + } + + /** + * Get the escalator row that has focus. + * + * @return The escalator row that contains a focused DOM element, or + * null if focus is outside of a body row. + */ + private Element getEscalatorRowWithFocus() { + Element activeRow = null; + + final Element activeElement = Util.getFocusedElement(); + + if (root.isOrHasChild(activeElement)) { + Element e = activeElement; + + while (e != null && e != root) { + /* + * You never know if there's several tables embedded in a + * cell... We'll take the deepest one. + */ + if (e.getTagName().equalsIgnoreCase("TR")) { + activeRow = e; + } + e = e.getParentElement(); + } + } + + return activeRow; + } } private class ColumnConfigurationImpl implements ColumnConfiguration { diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java index c2e73cc72c..f7af6a57e5 100644 --- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java +++ b/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java @@ -33,10 +33,15 @@ import com.vaadin.ui.TextField; @Widgetset(TestingWidgetSet.NAME) public class BasicEscalator extends AbstractTestUI { public static final String ESCALATOR = "escalator"; + public static final String INSERT_ROWS_OFFSET = "iro"; public static final String INSERT_ROWS_AMOUNT = "ira"; public static final String INSERT_ROWS_BUTTON = "irb"; + public static final String REMOVE_ROWS_OFFSET = "rro"; + public static final String REMOVE_ROWS_AMOUNT = "rra"; + public static final String REMOVE_ROWS_BUTTON = "rrb"; + private final Random random = new Random(); @Override @@ -71,8 +76,10 @@ public class BasicEscalator extends AbstractTestUI { final Layout removeRowsLayout = new HorizontalLayout(); final TextField removeRowsOffset = new TextField(); + removeRowsOffset.setId(REMOVE_ROWS_OFFSET); removeRowsLayout.addComponent(removeRowsOffset); final TextField removeRowsAmount = new TextField(); + removeRowsAmount.setId(REMOVE_ROWS_AMOUNT); removeRowsLayout.addComponent(removeRowsAmount); removeRowsLayout.addComponent(new Button("remove rows", new Button.ClickListener() { @@ -84,7 +91,11 @@ public class BasicEscalator extends AbstractTestUI { .getValue()); grid.removeRows(offset, amount); } - })); + }) { + { + setId(REMOVE_ROWS_BUTTON); + } + }); addComponent(removeRowsLayout); final Layout insertColumnsLayout = new HorizontalLayout(); diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java index 5658954e06..ba0b718f35 100644 --- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java @@ -17,11 +17,17 @@ package com.vaadin.tests.components.grid; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.Keys; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; @@ -32,6 +38,11 @@ import com.vaadin.tests.tb3.MultiBrowserTest; @TestCategory("grid") public class BasicEscalatorTest extends MultiBrowserTest { + private static final int SLEEP = 300; + + private static final Pattern ROW_PATTERN = Pattern + .compile("Row (\\d+): \\d+,\\d+"); + @Test public void testInitialState() throws Exception { openTestURL(); @@ -55,7 +66,7 @@ public class BasicEscalatorTest extends MultiBrowserTest { */ Thread.sleep(100); - scrollEscalatorVerticallyTo(1000); + setScrollTop(getVerticalScrollbar(), 1000); assertBodyCellWithContentIsFound("Row 50: 0,50"); } @@ -70,7 +81,7 @@ public class BasicEscalatorTest extends MultiBrowserTest { Thread.sleep(100); // scroll to bottom - scrollEscalatorVerticallyTo(100000000); + setScrollTop(getVerticalScrollbar(), 100000000); /* * this test does not test DOM reordering, therefore we don't rely on @@ -124,11 +135,6 @@ public class BasicEscalatorTest extends MultiBrowserTest { getDriver().get(testUrl); } - private void scrollEscalatorVerticallyTo(double px) { - executeScript("arguments[0].scrollTop = " + px, - getGridVerticalScrollbar()); - } - private Object executeScript(String script, WebElement element) { @SuppressWarnings("hiding") final WebDriver driver = getDriver(); @@ -142,9 +148,148 @@ public class BasicEscalatorTest extends MultiBrowserTest { } } - private WebElement getGridVerticalScrollbar() { - return getDriver() - .findElement( - By.xpath("//div[contains(@class, \"v-escalator-scroller-vertical\")]")); + @Test + public void domIsInitiallySorted() throws Exception { + openTestURL(); + + final List rows = getBodyRows(); + assertTrue("no body rows found", !rows.isEmpty()); + for (int i = 0; i < rows.size(); i++) { + String text = rows.get(i).getText(); + String expected = "Row " + i; + assertTrue("Expected \"" + expected + "...\" but was " + text, + text.startsWith(expected)); + } + } + + @Test + public void domIsSortedAfterInsert() throws Exception { + openTestURL(); + + final int rowsToInsert = 5; + final int offset = 5; + insertRows(offset, rowsToInsert); + + final List rows = getBodyRows(); + int i = 0; + for (; i < offset + rowsToInsert; i++) { + final String expectedStart = "Row " + i; + final String text = rows.get(i).getText(); + assertTrue("Expected \"" + expectedStart + "...\" but was " + text, + text.startsWith(expectedStart)); + } + + for (; i < rows.size(); i++) { + final String expectedStart = "Row " + (i - rowsToInsert); + final String text = rows.get(i).getText(); + assertTrue("(post insert) Expected \"" + expectedStart + + "...\" but was " + text, text.startsWith(expectedStart)); + } + } + + @Test + public void domIsSortedAfterRemove() throws Exception { + openTestURL(); + + final int rowsToRemove = 5; + final int offset = 5; + removeRows(offset, rowsToRemove); + + final List rows = getBodyRows(); + int i = 0; + for (; i < offset; i++) { + final String expectedStart = "Row " + i; + final String text = rows.get(i).getText(); + assertTrue("Expected " + expectedStart + "... but was " + text, + text.startsWith(expectedStart)); + } + + /* + * We check only up to 10, since after that, the indices are again + * reset, because new rows have been generated. The row numbers that + * they are given depends on the widget size, and it's too fragile to + * rely on some special assumptions on that. + */ + for (; i < 10; i++) { + final String expectedStart = "Row " + (i + rowsToRemove); + final String text = rows.get(i).getText(); + assertTrue("(post remove) Expected " + expectedStart + + "... but was " + text, text.startsWith(expectedStart)); + } + } + + @Test + public void domIsSortedAfterScroll() throws Exception { + openTestURL(); + setScrollTop(getVerticalScrollbar(), 500); + + /* + * Let the DOM reorder itself. + * + * TODO TestBench currently doesn't know when Grid's DOM structure is + * stable. There are some plans regarding implementing support for this, + * so this test case can (should) be modified once that's implemented. + */ + sleep(SLEEP); + + List rows = getBodyRows(); + int firstRowNumber = parseFirstRowNumber(rows); + + for (int i = 0; i < rows.size(); i++) { + final String expectedStart = "Row " + (i + firstRowNumber); + final String text = rows.get(i).getText(); + assertTrue("(post remove) Expected " + expectedStart + + "... but was " + text, text.startsWith(expectedStart)); + } + } + + private static int parseFirstRowNumber(List rows) + throws NumberFormatException { + final WebElement firstRow = rows.get(0); + final String firstRowText = firstRow.getText(); + final Matcher matcher = ROW_PATTERN.matcher(firstRowText); + if (!matcher.find()) { + fail("could not find " + ROW_PATTERN.pattern() + " in \"" + + firstRowText + "\""); + } + final String number = matcher.group(1); + return Integer.parseInt(number); + } + + private void insertRows(final int offset, final int amount) { + final WebElement offsetInput = vaadinElementById(BasicEscalator.INSERT_ROWS_OFFSET); + offsetInput.sendKeys(String.valueOf(offset), Keys.RETURN); + + final WebElement amountInput = vaadinElementById(BasicEscalator.INSERT_ROWS_AMOUNT); + amountInput.sendKeys(String.valueOf(amount), Keys.RETURN); + + final WebElement button = vaadinElementById(BasicEscalator.INSERT_ROWS_BUTTON); + button.click(); + } + + private void removeRows(final int offset, final int amount) { + final WebElement offsetInput = vaadinElementById(BasicEscalator.REMOVE_ROWS_OFFSET); + offsetInput.sendKeys(String.valueOf(offset), Keys.RETURN); + + final WebElement amountInput = vaadinElementById(BasicEscalator.REMOVE_ROWS_AMOUNT); + amountInput.sendKeys(String.valueOf(amount), Keys.RETURN); + + final WebElement button = vaadinElementById(BasicEscalator.REMOVE_ROWS_BUTTON); + button.click(); + } + + private void setScrollTop(WebElement element, long px) { + executeScript("arguments[0].scrollTop = " + px, element); + } + + private List getBodyRows() { + return getDriver().findElements(By.xpath("//tbody/tr/td[1]")); + } + + private WebElement getVerticalScrollbar() { + return getDriver().findElement( + By.xpath("//div[" + + "contains(@class, 'v-escalator-scroller-vertical')" + + "]")); } } -- cgit v1.2.3 From f1d796cddda7720fa59847d0df42c8a8dcf1c474 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 27 May 2014 11:13:17 +0300 Subject: Add basic functionality to GridElement class (#13334) Change-Id: I5340b000b87101cab4dacc700fc8251624f613f6 --- .../components/grid/GridBasicFeaturesTest.java | 60 +++++----- .../vaadin/tests/components/grid/GridElement.java | 126 +++++++++++++++++++++ 2 files changed, 160 insertions(+), 26 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index ac1951242c..a11b0f1be9 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -20,6 +20,7 @@ import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.util.ArrayList; import java.util.List; import org.junit.Test; @@ -29,6 +30,7 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import com.vaadin.testbench.TestBenchElement; import com.vaadin.tests.annotations.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; @@ -40,7 +42,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { openTestURL(); // Column headers should be visible - List cells = getGridHeaderRowCells(); + List cells = getGridHeaderRowCells(); assertEquals(10, cells.size()); assertEquals("Column0", cells.get(0).getText()); assertEquals("Column1", cells.get(1).getText()); @@ -52,7 +54,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { openTestURL(); // footer row should by default be hidden - List cells = getGridFooterRowCells(); + List cells = getGridFooterRowCells(); assertEquals(0, cells.size()); // Open footer row @@ -73,7 +75,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { // Hide column headers for this test selectMenuPath("Component", "Headers", "Visible"); - List cells = getGridHeaderRowCells(); + List cells = getGridHeaderRowCells(); // header row should be empty assertEquals(0, cells.size()); @@ -108,7 +110,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { selectMenuPath("Component", "Column groups", "Column group row 1", "Group Column 0 & 1"); - List cells = getGridFooterRowCells(); + List cells = getGridFooterRowCells(); assertEquals("Column 0 & 1", cells.get(0).getText()); } @@ -137,7 +139,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { openTestURL(); // Column 0 should be visible - List cells = getGridHeaderRowCells(); + List cells = getGridHeaderRowCells(); assertEquals("Column0", cells.get(0).getText()); // Hide column 0 @@ -153,7 +155,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { openTestURL(); // Column 0 should be visible - List cells = getGridHeaderRowCells(); + List cells = getGridHeaderRowCells(); assertEquals("Column0", cells.get(0).getText()); // Hide column 0 @@ -180,7 +182,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { sleep(1000); // Check that row is loaded - assertThat(getBodyCellByRowAndColumn(11, 1).getText(), not("...")); + assertThat(getBodyCellByRowAndColumn(11, 0).getText(), not("...")); } @Test @@ -190,10 +192,10 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { // Freeze column 2 selectMenuPath("Component", "Columns", "Column2", "Freeze"); - WebElement cell = getBodyCellByRowAndColumn(1, 1); + WebElement cell = getBodyCellByRowAndColumn(0, 0); assertTrue(cell.getAttribute("class").contains("frozen")); - cell = getBodyCellByRowAndColumn(1, 2); + cell = getBodyCellByRowAndColumn(0, 1); assertTrue(cell.getAttribute("class").contains("frozen")); } @@ -201,13 +203,13 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { public void testInitialColumnWidths() throws Exception { openTestURL(); - WebElement cell = getBodyCellByRowAndColumn(1, 1); + WebElement cell = getBodyCellByRowAndColumn(0, 0); assertEquals(100, cell.getSize().getWidth()); - cell = getBodyCellByRowAndColumn(1, 2); + cell = getBodyCellByRowAndColumn(0, 1); assertEquals(150, cell.getSize().getWidth()); - cell = getBodyCellByRowAndColumn(1, 3); + cell = getBodyCellByRowAndColumn(0, 2); assertEquals(200, cell.getSize().getWidth()); } @@ -216,27 +218,27 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { openTestURL(); // Default column width is 100px - WebElement cell = getBodyCellByRowAndColumn(1, 1); + WebElement cell = getBodyCellByRowAndColumn(0, 0); assertEquals(100, cell.getSize().getWidth()); // Set first column to be 200px wide selectMenuPath("Component", "Columns", "Column0", "Column0 Width", "200px"); - cell = getBodyCellByRowAndColumn(1, 1); + cell = getBodyCellByRowAndColumn(0, 0); assertEquals(200, cell.getSize().getWidth()); // Set second column to be 150px wide selectMenuPath("Component", "Columns", "Column1", "Column1 Width", "150px"); - cell = getBodyCellByRowAndColumn(1, 2); + cell = getBodyCellByRowAndColumn(0, 1); assertEquals(150, cell.getSize().getWidth()); // Set first column to be auto sized (defaults to 100px currently) selectMenuPath("Component", "Columns", "Column0", "Column0 Width", "Auto"); - cell = getBodyCellByRowAndColumn(1, 1); + cell = getBodyCellByRowAndColumn(0, 0); assertEquals(100, cell.getSize().getWidth()); } @@ -286,17 +288,17 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { openTestURL(); assertEquals("Unexpected cell initial state", "(0, 0)", - getBodyCellByRowAndColumn(1, 1).getText()); + getBodyCellByRowAndColumn(0, 0).getText()); selectMenuPath("Component", "Body rows", "Modify first row (getItemProperty)"); assertEquals("(First) modification with getItemProperty failed", - "modified: 0", getBodyCellByRowAndColumn(1, 1).getText()); + "modified: 0", getBodyCellByRowAndColumn(0, 0).getText()); selectMenuPath("Component", "Body rows", "Modify first row (getContainerProperty)"); assertEquals("(Second) modification with getItemProperty failed", - "modified: Column0", getBodyCellByRowAndColumn(1, 1).getText()); + "modified: Column0", getBodyCellByRowAndColumn(0, 0).getText()); } private void assertPrimaryStylename(String stylename) { @@ -316,9 +318,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { } private WebElement getBodyCellByRowAndColumn(int row, int column) { - return getDriver().findElement( - By.xpath("//div[@id='testComponent']//tbody/tr[" + row - + "]/td[" + column + "]")); + return getGridElement().getCell(row, column); } private void selectSubMenu(String menuCaption) { @@ -354,12 +354,20 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { return $(GridElement.class).id("testComponent"); } - private List getGridHeaderRowCells() { - return getGridElement().findElements(By.xpath(".//thead//th")); + private List getGridHeaderRowCells() { + List headerCells = new ArrayList(); + for (int i = 0; i < getGridElement().getHeaderCount(); ++i) { + headerCells.addAll(getGridElement().getHeaderCells(i)); + } + return headerCells; } - private List getGridFooterRowCells() { - return getGridElement().findElements(By.xpath(".//tfoot//td")); + private List getGridFooterRowCells() { + List footerCells = new ArrayList(); + for (int i = 0; i < getGridElement().getFooterCount(); ++i) { + footerCells.addAll(getGridElement().getFooterCells(i)); + } + return footerCells; } private void scrollGridVerticallyTo(double px) { diff --git a/uitest/src/com/vaadin/tests/components/grid/GridElement.java b/uitest/src/com/vaadin/tests/components/grid/GridElement.java index 51e07f6bb1..f743c553d9 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridElement.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridElement.java @@ -15,6 +15,12 @@ */ package com.vaadin.tests.components.grid; +import java.util.List; + +import org.openqa.selenium.NoSuchElementException; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.TestBenchElement; import com.vaadin.testbench.elements.AbstractComponentElement; import com.vaadin.testbench.elements.ServerClass; @@ -27,4 +33,124 @@ import com.vaadin.testbench.elements.ServerClass; @ServerClass("com.vaadin.ui.components.grid.Grid") public class GridElement extends AbstractComponentElement { + /** + * 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 TestBenchElement getCell(int rowIndex, int colIndex) { + scrollToRow(rowIndex); + return getSubPart("#cell[" + rowIndex + "][" + colIndex + "]"); + } + + /** + * Gets row element with given row index. + * + * @param index + * Row index + * @return Row element with given index. + */ + public TestBenchElement getRow(int index) { + scrollToRow(index); + return getSubPart("#cell[" + index + "]"); + } + + /** + * 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 TestBenchElement getHeaderCell(int rowIndex, int colIndex) { + return getSubPart("#header[" + rowIndex + "][" + colIndex + "]"); + } + + /** + * 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 TestBenchElement getFooterCell(int rowIndex, int colIndex) { + return getSubPart("#footer[" + rowIndex + "][" + colIndex + "]"); + } + + /** + * Gets list of header cell elements on given row. + * + * @param rowIndex + * Row index + * @return Header cell elements on given row. + */ + public List getHeaderCells(int rowIndex) { + return TestBenchElement.wrapElements( + getSubPart("#header[" + rowIndex + "]").findElements( + By.xpath("./th")), getTestBenchCommandExecutor()); + } + + /** + * Gets list of header cell elements on given row. + * + * @param rowIndex + * Row index + * @return Header cell elements on given row. + */ + public List getFooterCells(int rowIndex) { + return TestBenchElement.wrapElements( + getSubPart("#footer[" + rowIndex + "]").findElements( + By.xpath("./td")), getTestBenchCommandExecutor()); + } + + /** + * 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(); + } + + /** + * 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)); + } } -- cgit v1.2.3 From aa4e06093ae7b887dad57559e057d07e4e9aea5c Mon Sep 17 00:00:00 2001 From: Leif Ã…strand Date: Fri, 30 May 2014 13:36:27 +0300 Subject: Add caching logic for Grid DataSource (#13334) Change-Id: Ia9323bf4d3e26c0f9425f363af56f41bdcf1d39d --- .../client/data/AbstractRemoteDataSource.java | 98 +++++++++-- .../src/com/vaadin/client/data/CacheStrategy.java | 183 +++++++++++++++++++++ .../tests/components/grid/GridBasicFeatures.java | 10 +- 3 files changed, 272 insertions(+), 19 deletions(-) create mode 100644 client/src/com/vaadin/client/data/CacheStrategy.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java index 40f5111f8a..6edb73b4df 100644 --- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java +++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java @@ -19,6 +19,7 @@ package com.vaadin.client.data; import java.util.HashMap; import java.util.List; +import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.vaadin.client.Profiler; @@ -40,7 +41,13 @@ import com.vaadin.shared.ui.grid.Range; */ public abstract class AbstractRemoteDataSource implements DataSource { - private boolean requestPending = false; + /** + * Records the start of the previously requested range. This is used when + * tracking request timings to distinguish between explicit responses and + * arbitrary updates pushed from the server. + */ + private int lastRequestStart = -1; + private double pendingRequestTime; private boolean coverageCheckPending = false; @@ -52,7 +59,9 @@ public abstract class AbstractRemoteDataSource implements DataSource { private DataChangeHandler dataChangeHandler; - private int estimatedSize; + private Range estimatedAvailableRange = Range.between(0, 0); + + private CacheStrategy cacheStrategy = new CacheStrategy.DefaultCacheStrategy(); private final ScheduledCommand coverageChecker = new ScheduledCommand() { @Override @@ -70,7 +79,7 @@ public abstract class AbstractRemoteDataSource implements DataSource { */ protected void setEstimatedSize(int estimatedSize) { // TODO update dataChangeHandler if size changes - this.estimatedSize = estimatedSize; + estimatedAvailableRange = Range.withLength(0, estimatedSize); } private void ensureCoverageCheck() { @@ -92,14 +101,16 @@ public abstract class AbstractRemoteDataSource implements DataSource { } private void checkCacheCoverage() { - if (requestPending) { - // Anyone clearing requestPending should run this method again + if (lastRequestStart != -1) { + // Anyone clearing lastRequestStart should run this method again return; } Profiler.enter("AbstractRemoteDataSource.checkCacheCoverage"); - if (!requestedAvailability.intersects(cached) || cached.isEmpty()) { + Range minCacheRange = getMinCacheRange(); + + if (!minCacheRange.intersects(cached) || cached.isEmpty()) { /* * Simple case: no overlap between cached data and needed data. * Clear the cache and request new data @@ -107,22 +118,24 @@ public abstract class AbstractRemoteDataSource implements DataSource { rowCache.clear(); cached = Range.between(0, 0); - handleMissingRows(requestedAvailability); + handleMissingRows(getMaxCacheRange()); } else { discardStaleCacheEntries(); // Might need more rows -> request them - Range[] availabilityPartition = requestedAvailability - .partitionWith(cached); - handleMissingRows(availabilityPartition[0]); - handleMissingRows(availabilityPartition[2]); + if (!minCacheRange.isSubsetOf(cached)) { + Range[] missingCachePartition = getMaxCacheRange() + .partitionWith(cached); + handleMissingRows(missingCachePartition[0]); + handleMissingRows(missingCachePartition[2]); + } } Profiler.leave("AbstractRemoteDataSource.checkCacheCoverage"); } private void discardStaleCacheEntries() { - Range[] cacheParition = cached.partitionWith(requestedAvailability); + Range[] cacheParition = cached.partitionWith(getMaxCacheRange()); dropFromCache(cacheParition[0]); cached = cacheParition[1]; dropFromCache(cacheParition[2]); @@ -138,7 +151,8 @@ public abstract class AbstractRemoteDataSource implements DataSource { if (range.isEmpty()) { return; } - requestPending = true; + lastRequestStart = range.getStart(); + pendingRequestTime = Duration.currentTimeMillis(); requestRows(range.getStart(), range.length()); } @@ -156,7 +170,7 @@ public abstract class AbstractRemoteDataSource implements DataSource { @Override public int getEstimatedSize() { - return estimatedSize; + return estimatedAvailableRange.length(); } @Override @@ -183,13 +197,21 @@ public abstract class AbstractRemoteDataSource implements DataSource { * a list of rows, starting from firstRowIndex */ protected void setRowData(int firstRowIndex, List rowData) { - requestPending = false; Profiler.enter("AbstractRemoteDataSource.setRowData"); Range received = Range.withLength(firstRowIndex, rowData.size()); - Range[] partition = received.partitionWith(requestedAvailability); + if (firstRowIndex == lastRequestStart) { + // Provide timing information if we know when we asked for this data + cacheStrategy.onDataArrive(Duration.currentTimeMillis() + - pendingRequestTime, received.length()); + } + lastRequestStart = -1; + + Range maxCacheRange = getMaxCacheRange(); + + Range[] partition = received.partitionWith(maxCacheRange); Range newUsefulData = partition[1]; if (!newUsefulData.isEmpty()) { @@ -268,7 +290,7 @@ public abstract class AbstractRemoteDataSource implements DataSource { .length()); cached = remainsBefore.combineWith(transposedRemainsAfter); } - estimatedSize -= count; + setEstimatedSize(getEstimatedSize() - count); dataChangeHandler.dataRemoved(firstRowIndex, count); checkCacheCoverage(); @@ -314,7 +336,7 @@ public abstract class AbstractRemoteDataSource implements DataSource { } } - estimatedSize += count; + setEstimatedSize(getEstimatedSize() + count); dataChangeHandler.dataAdded(firstRowIndex, count); checkCacheCoverage(); @@ -329,4 +351,44 @@ public abstract class AbstractRemoteDataSource implements DataSource { public Range getCachedRange() { return cached; } + + /** + * Sets the cache strategy that is used to determine how much data is + * fetched and cached. + *

+ * The new strategy is immediately used to evaluate whether currently cached + * rows should be discarded or new rows should be fetched. + * + * @param cacheStrategy + * a cache strategy implementation, not null + */ + public void setCacheStrategy(CacheStrategy cacheStrategy) { + if (cacheStrategy == null) { + throw new IllegalArgumentException(); + } + + if (this.cacheStrategy != cacheStrategy) { + this.cacheStrategy = cacheStrategy; + + checkCacheCoverage(); + } + } + + private Range getMinCacheRange() { + Range minCacheRange = cacheStrategy.getMinCacheRange( + requestedAvailability, cached, estimatedAvailableRange); + + assert minCacheRange.isSubsetOf(estimatedAvailableRange); + + return minCacheRange; + } + + private Range getMaxCacheRange() { + Range maxCacheRange = cacheStrategy.getMaxCacheRange( + requestedAvailability, cached, estimatedAvailableRange); + + assert maxCacheRange.isSubsetOf(estimatedAvailableRange); + + return maxCacheRange; + } } diff --git a/client/src/com/vaadin/client/data/CacheStrategy.java b/client/src/com/vaadin/client/data/CacheStrategy.java new file mode 100644 index 0000000000..79ce537314 --- /dev/null +++ b/client/src/com/vaadin/client/data/CacheStrategy.java @@ -0,0 +1,183 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.client.data; + +import com.vaadin.shared.ui.grid.Range; + +/** + * Determines what data an {@link AbstractRemoteDataSource} should fetch and + * keep cached. + * + * @since 7.4 + * @author Vaadin Ltd + */ +public interface CacheStrategy { + /** + * A helper class for creating a simple symmetric cache strategy that uses + * the same logic for both rows before and after the currently cached range. + *

+ * This simple approach rules out more advanced heuristics that would take + * the current scrolling direction or past scrolling behavior into account. + */ + public static abstract class AbstractBasicSymmetricalCacheStrategy + implements CacheStrategy { + + @Override + public void onDataArrive(double roundTripTime, int rowCount) { + // NOP + } + + @Override + public Range getMinCacheRange(Range displayedRange, Range cachedRange, + Range estimatedAvailableRange) { + int cacheSize = getMinimumCacheSize(displayedRange.length()); + + return displayedRange.expand(cacheSize, cacheSize).restrictTo( + estimatedAvailableRange); + } + + @Override + public Range getMaxCacheRange(Range displayedRange, Range cachedRange, + Range estimatedAvailableRange) { + int cacheSize = getMaximumCacheSize(displayedRange.length()); + + return displayedRange.expand(cacheSize, cacheSize).restrictTo( + estimatedAvailableRange); + } + + /** + * Gets the maximum number of extra items to cache in one direction. + * + * @param pageSize + * the current number of items used at once + * @return maximum of items to cache + */ + public abstract int getMaximumCacheSize(int pageSize); + + /** + * Gets the the minimum number of extra items to cache in one direction. + * + * @param pageSize + * the current number of items used at once + * @return minimum number of items to cache + */ + public abstract int getMinimumCacheSize(int pageSize); + } + + /** + * The default cache strategy used by {@link AbstractRemoteDataSource}, + * using multiples of the page size for determining the minimum and maximum + * number of items to keep in the cache. By default, at least three times + * the page size both before and after the currently used range are kept in + * the cache and items are discarded if there's yet another page size worth + * of items cached in either direction. + */ + public static class DefaultCacheStrategy extends + AbstractBasicSymmetricalCacheStrategy { + private final int minimumRatio; + private final int maximumRatio; + + /** + * Creates a DefaultCacheStrategy keeping between 3 and 4 pages worth of + * data cached both before and after the active range. + */ + public DefaultCacheStrategy() { + this(3, 4); + } + + /** + * Creates a DefaultCacheStrategy with custom ratios for how much data + * to cache. The ratios denote how many multiples of the currently used + * page size are kept in the cache in each direction. + * + * @param minimumRatio + * the minimum number of pages to keep in the cache in each + * direction + * @param maximumRatio + * the maximum number of pages to keep in the cache in each + * direction + */ + public DefaultCacheStrategy(int minimumRatio, int maximumRatio) { + this.minimumRatio = minimumRatio; + this.maximumRatio = maximumRatio; + } + + @Override + public int getMinimumCacheSize(int pageSize) { + return pageSize * minimumRatio; + } + + @Override + public int getMaximumCacheSize(int pageSize) { + return pageSize * maximumRatio; + } + } + + /** + * Called whenever data requested by the data source has arrived. This + * information can e.g. be used for measuring how long it takes to fetch + * different number of rows from the server. + *

+ * A cache strategy implementation cannot use this information to keep track + * of which items are in the cache since the data source might discard items + * without notifying the cache strategy. + * + * @param roundTripTime + * the total number of milliseconds elapsed from requesting the + * data until the response was passed to the data source + * @param rowCount + * the number of received rows + */ + public void onDataArrive(double roundTripTime, int rowCount); + + /** + * Gets the minimum row range that should be cached. The data source will + * fetch new data if the currently cached range does not fill the entire + * minimum cache range. + * + * @param displayedRange + * the range of currently displayed rows + * @param cachedRange + * the range of currently cached rows + * @param estimatedAvailableRange + * the estimated range of rows available for the data source + * + * @return the minimum range of rows that should be cached, should at least + * include the displayed range and should not exceed the total + * estimated available range + */ + public Range getMinCacheRange(Range displayedRange, Range cachedRange, + Range estimatedAvailableRange); + + /** + * Gets the maximum row range that should be cached. The data source will + * discard cached rows that are outside the maximum range. + * + * @param displayedRange + * the range of currently displayed rows + * @param cachedRange + * the range of currently cached rows + * @param estimatedAvailableRange + * the estimated range of rows available for the data source + * + * @return the maximum range of rows that should be cached, should at least + * include the displayed range and should not exceed the total + * estimated available range + */ + public Range getMaxCacheRange(Range displayedRange, Range cachedRange, + Range estimatedAvailableRange); +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index 9fb962c495..91bd6b032d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -18,6 +18,7 @@ package com.vaadin.tests.components.grid; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; @@ -48,7 +49,14 @@ public class GridBasicFeatures extends AbstractComponentTest { protected Grid constructComponent() { // Build data source - ds = new IndexedContainer(); + ds = new IndexedContainer() { + @Override + public List getItemIds(int startIndex, int numberOfIds) { + log("Requested items " + startIndex + " - " + + (startIndex + numberOfIds)); + return super.getItemIds(startIndex, numberOfIds); + } + }; for (int col = 0; col < COLUMNS; col++) { ds.addContainerProperty(getColumnProperty(col), String.class, ""); -- cgit v1.2.3 From 37436ce6448c8bc20bb866a5c259f58e8f50c0c3 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Thu, 22 May 2014 15:54:36 +0300 Subject: Client-side selection checkbox renderer (#13334) Change-Id: I7b6a5c4ca1d78a97c34b1f7b95d1488edeb8551e --- client/src/com/vaadin/client/ui/grid/Grid.java | 168 ++++++++++++++++++++- .../ui/grid/selection/MultiSelectionRenderer.java | 34 +++++ server/src/com/vaadin/ui/components/grid/Grid.java | 5 + .../src/com/vaadin/shared/ui/grid/GridState.java | 5 + .../tests/components/grid/GridBasicFeatures.java | 8 + 5 files changed, 214 insertions(+), 6 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 44e0edce8e..0d8c8f9ba9 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -38,6 +38,7 @@ import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.TextRenderer; +import com.vaadin.client.ui.grid.selection.MultiSelectionRenderer; import com.vaadin.shared.ui.grid.GridConstants; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.Range; @@ -78,6 +79,92 @@ import com.vaadin.shared.util.SharedUtil; */ public class Grid extends Composite implements SubPartAware { + private class SelectionColumn extends GridColumn { + private boolean initDone = false; + + public SelectionColumn(final Renderer selectColumnRenderer) { + super(selectColumnRenderer); + + setHeaderRenderer(new Renderer() { + @Override + public void render(FlyweightCell cell, String data) { + if (cell.getRow() == escalator.getHeader().getRowCount() - 1) { + selectColumnRenderer.render(cell, Boolean.FALSE); + } + } + }); + } + + public void initDone() { + initDone = true; + } + + @Override + public void setFooterCaption(String caption) { + if (initDone) { + throw new UnsupportedOperationException( + "The selection column is read only"); + } else { + super.setFooterCaption(caption); + } + } + + @Override + public void setFooterRenderer(Renderer renderer) { + if (initDone) { + throw new UnsupportedOperationException( + "The selection column is read only"); + } else { + super.setFooterRenderer(renderer); + } + } + + @Override + public void setHeaderCaption(String caption) { + if (initDone) { + throw new UnsupportedOperationException( + "The selection column is read only"); + } else { + super.setHeaderCaption(caption); + } + } + + @Override + public void setHeaderRenderer(Renderer renderer) { + if (initDone) { + throw new UnsupportedOperationException( + "The selection column is read only"); + } else { + super.setHeaderRenderer(renderer); + } + } + + @Override + public void setVisible(boolean visible) { + if (initDone) { + throw new UnsupportedOperationException( + "The selection column is read only"); + } else { + super.setVisible(visible); + } + } + + @Override + public void setWidth(int pixels) { + if (initDone) { + throw new UnsupportedOperationException( + "The selection column is read only"); + } else { + super.setWidth(pixels); + } + } + + @Override + public Boolean getValue(T row) { + return Boolean.valueOf(isSelected(row)); + } + } + /** * Escalator used internally by grid to render the rows */ @@ -114,6 +201,10 @@ public class Grid extends Composite implements SubPartAware { */ private GridColumn lastFrozenColumn; + private Renderer selectColumnRenderer = null; + + private SelectionColumn selectionColumn; + /** * Base class for grid columns internally used by the Grid. The user should * use {@link GridColumn} when creating new columns. @@ -215,10 +306,12 @@ public class Grid extends Composite implements SubPartAware { this.grid = grid; - setVisible(this.visible); - setWidth(this.width); - setHeaderCaption(this.header); - setFooterCaption(this.footer); + if (grid != null) { + setVisible(this.visible); + setWidth(this.width); + setHeaderCaption(this.header); + setFooterCaption(this.footer); + } } /** @@ -796,8 +889,7 @@ public class Grid extends Composite implements SubPartAware { * the column to add */ public void addColumn(GridColumn column) { - ColumnConfiguration conf = escalator.getColumnConfiguration(); - addColumn(column, conf.getColumnCount()); + addColumn(column, getColumnCount()); } /** @@ -807,9 +899,24 @@ public class Grid extends Composite implements SubPartAware { * the index where the column should be inserted into * @param column * the column to add + * @throws IllegalStateException + * if Grid's current selection model renders a selection column, + * and {@code index} is 0. */ public void addColumn(GridColumn column, int index) { + if (column == selectionColumn) { + throw new IllegalArgumentException("The selection column many " + + "not be added manually"); + } else if (selectionColumn != null && index == 0) { + throw new IllegalStateException("A column cannot be inserted " + + "before the selection column"); + } + addColumnSkipSelectionColumnCheck(column, index); + } + + private void addColumnSkipSelectionColumnCheck(GridColumn column, + int index) { // Register column with grid columns.add(index, column); @@ -889,7 +996,15 @@ public class Grid extends Composite implements SubPartAware { * the column to remove */ public void removeColumn(GridColumn column) { + if (column != null && column.equals(selectionColumn)) { + throw new IllegalArgumentException( + "The selection column may not be removed manually."); + } + + removeColumnSkipSelectionColumnCheck(column); + } + private void removeColumnSkipSelectionColumnCheck(GridColumn column) { int columnIndex = columns.indexOf(column); int visibleIndex = findVisibleColumnIndex(column); columns.remove(columnIndex); @@ -1559,4 +1674,45 @@ public class Grid extends Composite implements SubPartAware { } return null; } + + private void setSelectColumnRenderer( + final Renderer selectColumnRenderer) { + if (this.selectColumnRenderer == selectColumnRenderer) { + return; + } + + if (this.selectColumnRenderer != null) { + removeColumnSkipSelectionColumnCheck(selectionColumn); + } + + this.selectColumnRenderer = selectColumnRenderer; + + if (selectColumnRenderer != null) { + selectionColumn = new SelectionColumn(selectColumnRenderer); + + // FIXME: this needs to be done elsewhere, requires design... + selectionColumn.setWidth(25); + addColumnSkipSelectionColumnCheck(selectionColumn, 0); + selectionColumn.initDone(); + } else { + selectionColumn = null; + } + } + + /* TODO remove before final */ + public void setSelectionCheckboxes(boolean set) { + if (set) { + setSelectColumnRenderer(new MultiSelectionRenderer()); + } else { + setSelectColumnRenderer(null); + } + } + + /* + * This is the same client-side Grid "isSelected" method as in the selection + * model design. + */ + private boolean isSelected(T row) { + return false; + } } diff --git a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java new file mode 100644 index 0000000000..847c897b43 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.selection; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.user.client.DOM; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Renderer; + +/* This class will probably not survive the final merge of all selection functionality. */ +public class MultiSelectionRenderer implements Renderer { + @Override + public void render(FlyweightCell cell, Boolean data) { + Element checkbox = Element.as(DOM.createInputCheck()); + if (Boolean.TRUE.equals(data)) { + checkbox.setAttribute("checked", "checked"); + } + cell.getElement().removeAllChildren(); + cell.getElement().appendChild(checkbox); + } +} diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 49b3f1fa64..7f3e3440c7 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -925,4 +925,9 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { removeListener(SelectionChangeEvent.class, listener, SELECTION_CHANGE_METHOD); } + + /** FIXME remove once selection mode communcation is done. only for testing. */ + public void setSelectionCheckboxes(boolean value) { + getState().selectionCheckboxes = value; + } } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index 8fdd8c8ec5..acb2a48e3c 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.annotations.DelegateToWidget; /** * The shared state for the {@link com.vaadin.ui.components.grid.Grid} component @@ -85,4 +86,8 @@ public class GridState extends AbstractComponentState { */ public HeightMode heightMode = HeightMode.CSS; + /** FIXME remove once selection mode communcation is done. only for testing. */ + @DelegateToWidget + public boolean selectionCheckboxes; + } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index 91bd6b032d..1dc500202e 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -147,6 +147,14 @@ public class GridBasicFeatures extends AbstractComponentTest { protected void createColumnActions() { createCategory("Columns", null); + createBooleanAction("Selection controls", "Columns", false, + new Command() { + @Override + public void execute(Grid grid, Boolean value, Object data) { + grid.setSelectionCheckboxes(value); + } + }); + for (int c = 0; c < COLUMNS; c++) { createCategory(getColumnProperty(c), "Columns"); -- cgit v1.2.3 From 1da445ac8c13970a662eb417203950d643548946 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Mon, 2 Jun 2014 13:59:01 +0300 Subject: Add (pre|post)(Attach|Detach) methods to EscalatorUpdater (#13334) These are not called by anything yet. Change-Id: If902afe1a2040b506fd6bf43de79cd0ebc793387 --- .../src/com/vaadin/client/ui/grid/Escalator.java | 2 +- .../vaadin/client/ui/grid/EscalatorUpdater.java | 102 +++++++++++++++++++-- client/src/com/vaadin/client/ui/grid/Grid.java | 43 ++++++++- .../tests/widgetset/client/grid/VTestGrid.java | 32 +++++-- 4 files changed, 161 insertions(+), 18 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index 53c70bbb70..9f159b018c 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -1352,7 +1352,7 @@ public class Escalator extends Widget { void refreshRow(final Node tr, final int logicalRowIndex) { flyweightRow.setup((Element) tr, logicalRowIndex, columnConfiguration.getCalculatedColumnWidths()); - updater.updateCells(flyweightRow, flyweightRow.getCells()); + updater.update(flyweightRow, flyweightRow.getCells()); /* * the "assert" guarantees that this code is run only during diff --git a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java index c6fe90850a..22cf55cf79 100644 --- a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java +++ b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java @@ -32,13 +32,41 @@ package com.vaadin.client.ui.grid; * @see Escalator#getFooter() */ public interface EscalatorUpdater { - /** An {@link EscalatorUpdater} that doesn't render anything. */ + + /** + * An {@link EscalatorUpdater} that doesn't render anything. + */ public static final EscalatorUpdater NULL = new EscalatorUpdater() { @Override - public void updateCells(final Row row, + public void update(final Row row, final Iterable cellsToUpdate) { // NOOP } + + @Override + public void preAttach(final Row row, + final Iterable cellsToAttach) { + // NOOP + + } + + @Override + public void postAttach(final Row row, + final Iterable attachedCells) { + // NOOP + } + + @Override + public void preDetach(final Row row, + final Iterable cellsToDetach) { + // NOOP + } + + @Override + public void postDetach(final Row row, + final Iterable detachedCells) { + // NOOP + } }; /** @@ -54,12 +82,70 @@ public interface EscalatorUpdater { * data in a cell. * * @param row - * information about the row to update. Note: You should - * not store nor reuse this reference + * Information about the row that is being updated. + * Note: You should not store nor reuse this reference. * @param cellsToUpdate - * a collection of cells which need to be updated. Note: - * You should neither store nor reuse the reference to the list, - * nor to the individual cells + * A collection of cells which need to be updated. Note: + * You should neither store nor reuse the reference to the + * iterable, nor to the individual cells. */ - public void updateCells(Row row, Iterable cellsToUpdate); + public void update(Row row, Iterable cellsToUpdate); + + /** + * Called before attaching new cells to the escalator. + * + * @param row + * Information about the row to which the cells will be added. + * Note: You should not store nor reuse this reference. + * @param cellsToAttach + * A collection of cells that are about to be attached. + * Note: You should neither store nor reuse the + * reference to the iterable, nor to the individual cells. + * + */ + public void preAttach(Row row, Iterable cellsToAttach); + + /** + * Called after attaching new cells to the escalator. + * + * @param row + * Information about the row to which the cells were added. + * Note: You should not store nor reuse this reference. + * @param attachedCells + * A collection of cells that were attached. Note: You + * should neither store nor reuse the reference to the iterable, + * nor to the individual cells. + * + */ + public void postAttach(Row row, Iterable attachedCells); + + /** + * Called before detaching cells from the escalator. + * + * @param row + * Information about the row from which the cells will be + * removed. Note: You should not store nor reuse this + * reference. + * @param cellsToAttach + * A collection of cells that are about to be detached. + * Note: You should neither store nor reuse the + * reference to the iterable, nor to the individual cells. + * + */ + public void preDetach(Row row, Iterable cellsToDetach); + + /** + * Called after detaching cells from the escalator. + * + * @param row + * Information about the row from which the cells were removed. + * Note: You should not store nor reuse this reference. + * @param attachedCells + * A collection of cells that were detached. Note: You + * should neither store nor reuse the reference to the iterable, + * nor to the individual cells. + * + */ + public void postDetach(Row row, Iterable detachedCells); + } diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 0d8c8f9ba9..25a0cd3f81 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -614,7 +614,7 @@ public class Grid extends Composite implements SubPartAware { public abstract Renderer getGroupRenderer(ColumnGroup group); @Override - public void updateCells(Row row, Iterable cellsToUpdate) { + public void update(Row row, Iterable cellsToUpdate) { int rowIndex; if (inverted) { @@ -673,6 +673,22 @@ public class Grid extends Composite implements SubPartAware { } } } + + @Override + public void preAttach(Row row, Iterable cellsToAttach) { + } + + @Override + public void postAttach(Row row, Iterable attachedCells) { + } + + @Override + public void preDetach(Row row, Iterable cellsToDetach) { + } + + @Override + public void postDetach(Row row, Iterable detachedCells) { + } } /** @@ -757,8 +773,7 @@ public class Grid extends Composite implements SubPartAware { return new EscalatorUpdater() { @Override - public void updateCells(Row row, - Iterable cellsToUpdate) { + public void update(Row row, Iterable cellsToUpdate) { int rowIndex = row.getRow(); if (dataSource == null) { setCellsLoading(cellsToUpdate); @@ -786,6 +801,28 @@ public class Grid extends Composite implements SubPartAware { cell.getElement().setInnerText("..."); } } + + @Override + public void preAttach(Row row, Iterable cellsToAttach) { + // NOOP for now + } + + @Override + public void postAttach(Row row, + Iterable attachedCells) { + // NOOP for now + } + + @Override + public void preDetach(Row row, Iterable cellsToDetach) { + // NOOP for now + } + + @Override + public void postDetach(Row row, + Iterable detachedCells) { + // NOOP for now + } }; } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java index dcbe367bb2..fbce00fc11 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java @@ -15,6 +15,26 @@ import com.vaadin.shared.ui.grid.ScrollDestination; public class VTestGrid extends Composite { + private static abstract class TestEscalatorUpdater implements + EscalatorUpdater { + + @Override + public void preAttach(Row row, Iterable cellsToAttach) { + } + + @Override + public void postAttach(Row row, Iterable attachedCells) { + } + + @Override + public void preDetach(Row row, Iterable cellsToDetach) { + } + + @Override + public void postDetach(Row row, Iterable detachedCells) { + } + } + private static class Data { private int columnCounter = 0; private int rowCounter = 0; @@ -40,9 +60,9 @@ public class VTestGrid extends Composite { } public EscalatorUpdater createHeaderUpdater() { - return new EscalatorUpdater() { + return new TestEscalatorUpdater() { @Override - public void updateCells(final Row row, + public void update(final Row row, final Iterable cellsToUpdate) { for (final FlyweightCell cell : cellsToUpdate) { if (cell.getColumn() % 3 == 0) { @@ -58,9 +78,9 @@ public class VTestGrid extends Composite { } public EscalatorUpdater createFooterUpdater() { - return new EscalatorUpdater() { + return new TestEscalatorUpdater() { @Override - public void updateCells(final Row row, + public void update(final Row row, final Iterable cellsToUpdate) { for (final FlyweightCell cell : cellsToUpdate) { if (cell.getColumn() % 3 == 1) { @@ -76,7 +96,7 @@ public class VTestGrid extends Composite { } public EscalatorUpdater createBodyUpdater() { - return new EscalatorUpdater() { + return new TestEscalatorUpdater() { private int i = 0; public void renderCell(final FlyweightCell cell) { @@ -122,7 +142,7 @@ public class VTestGrid extends Composite { } @Override - public void updateCells(final Row row, + public void update(final Row row, final Iterable cellsToUpdate) { for (final FlyweightCell cell : cellsToUpdate) { renderCell(cell); -- cgit v1.2.3 From 0411cfee5dde30bba72290e4c81aa1229a5d6ab5 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Tue, 3 Jun 2014 13:52:33 +0300 Subject: Implemented WidgetRenderer #12993 Change-Id: I6eb69bd0c18adba057e9785778e0392e1ff25a22 --- .../src/com/vaadin/client/ui/grid/Escalator.java | 36 +--- .../com/vaadin/client/ui/grid/FlyweightCell.java | 57 ------- client/src/com/vaadin/client/ui/grid/Grid.java | 98 +++++++---- .../client/ui/grid/renderers/WidgetRenderer.java | 67 ++++++++ .../tests/components/grid/GridClientRenderers.java | 94 +++++++++++ .../grid/GridClientColumnRendererConnector.java | 186 +++++++++++++++++++++ .../client/grid/GridClientColumnRendererRpc.java | 33 ++++ .../server/grid/GridClientColumnRenderers.java | 98 +++++++++++ 8 files changed, 549 insertions(+), 120 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index e25e1a2851..3af7c76da8 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -1197,10 +1197,6 @@ public class Escalator extends Widget { getEscalatorUpdater().preDetach(flyweightRow, flyweightRow.getCells()); - for (int c = 0; c < tr.getChildCount(); c++) { - // TODO this should be WidgetRenderer's responsibility - detachPossibleWidgetFromCell((Element) tr.getChild(c).cast()); - } tr.removeFromParent(); getEscalatorUpdater().postDetach(flyweightRow, @@ -1503,7 +1499,6 @@ public class Escalator extends Widget { for (FlyweightCell cell : cells) { Element cellElement = cell.getElement(); - detachPossibleWidgetFromCell(cellElement); cellElement.removeFromParent(); } @@ -1555,18 +1550,6 @@ public class Escalator extends Widget { } } - void detachPossibleWidgetFromCell(Node cellNode) { - // Detach possible widget - Widget widget = getWidgetFromCell(cellNode); - if (widget != null) { - // Orphan. - setParent(widget, null); - - // Physical detach. - cellNode.removeChild(widget.getElement()); - } - } - protected void paintInsertColumns(final int offset, final int numberOfColumns, boolean frozen) { final NodeList childNodes = root.getChildNodes(); @@ -1620,7 +1603,7 @@ public class Escalator extends Widget { * Precondition: The row must be already attached to the DOM and the * FlyweightCell instances corresponding to the new columns added to * {@code flyweightRow}. - * + * * @param tr * the row in which to insert the cells * @param logicalRowIndex @@ -3340,10 +3323,6 @@ public class Escalator extends Widget { .listIterator(visualRowOrder.size()); for (int i = 0; i < -neededEscalatorRowsDiff; i++) { final Element last = iter.previous(); - for (int c = 0; c < last.getChildCount(); c++) { - detachPossibleWidgetFromCell((Element) last.getChild(c) - .cast()); - } last.removeFromParent(); iter.remove(); } @@ -4404,19 +4383,6 @@ public class Escalator extends Widget { body.getLogicalRowIndex(body.visualRowOrder.getLast()) + 1); } - /** - * Accesses the package private method Widget#setParent() - * - * @param widget - * The widget to access - * @param parent - * The parent to set - */ - static native final void setParent(Widget widget, Widget parent) - /*-{ - widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent); - }-*/; - /** * Returns the widget from a cell node or null if there is no * widget in the cell diff --git a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java index 1b956258ff..a7d0ffa989 100644 --- a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java +++ b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java @@ -20,8 +20,6 @@ import java.util.List; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Unit; -import com.google.gwt.user.client.ui.IsWidget; -import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.grid.FlyweightRow.CellIterator; /** @@ -185,59 +183,4 @@ public class FlyweightCell { } } } - - /** - * @deprecated Will be removed in further refactorings - */ - @Deprecated - public Widget getWidget() { - return Escalator.getWidgetFromCell(getElement()); - } - - /** - * @deprecated Will be removed in further refactorings - */ - @Deprecated - public void setWidget(Widget widget) { - - Widget oldWidget = getWidget(); - - // Validate - if (oldWidget == widget) { - return; - } - - // Detach old child. - if (oldWidget != null) { - // Orphan. - Escalator.setParent(oldWidget, null); - - // Physical detach. - getElement().removeChild(oldWidget.getElement()); - } - - // Remove any previous text nodes from previous - // setInnerText/setInnerHTML - getElement().removeAllChildren(); - - // Attach new child. - if (widget != null) { - // Detach new child from old parent. - widget.removeFromParent(); - - // Physical attach. - getElement().appendChild(widget.getElement()); - - Escalator.setParent(widget, escalator); - } - } - - /** - * @deprecated Will be removed in further refactorings - */ - @Deprecated - public void setWidget(IsWidget w) { - setWidget(Widget.asWidgetOrNull(w)); - } - } diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 0c38e984c1..4bb13990a5 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -33,11 +33,14 @@ import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HasVisibility; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.Util; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.TextRenderer; +import com.vaadin.client.ui.grid.renderers.WidgetRenderer; import com.vaadin.client.ui.grid.selection.MultiSelectionRenderer; import com.vaadin.shared.ui.grid.GridConstants; import com.vaadin.shared.ui.grid.HeightMode; @@ -774,49 +777,68 @@ public class Grid extends Composite implements SubPartAware { return new EscalatorUpdater() { @Override - public void update(Row row, Iterable cellsToUpdate) { - int rowIndex = row.getRow(); - if (dataSource == null) { - setCellsLoading(cellsToUpdate); - return; + public void preAttach(Row row, Iterable cellsToAttach) { + // NOP + } + + @Override + public void postAttach(Row row, + Iterable attachedCells) { + for (FlyweightCell cell : attachedCells) { + Renderer renderer = findRenderer(cell); + if (renderer instanceof WidgetRenderer) { + WidgetRenderer widgetRenderer = (WidgetRenderer) renderer; + + Widget widget = widgetRenderer.createWidget(); + assert widget != null : "WidgetRenderer.createWidget() returned null. It should return a widget."; + assert widget.getParent() == null : "WidgetRenderer.createWidget() returned a widget which already is attached."; + assert cell.getElement().getChildCount() == 0 : "Cell content should be empty when adding Widget"; + + // Physical attach + cell.getElement().appendChild(widget.getElement()); + + // Logical attach + setParent(widget, Grid.this); + } } + } + @Override + public void update(Row row, Iterable cellsToUpdate) { + int rowIndex = row.getRow(); T rowData = dataSource.getRow(rowIndex); if (rowData == null) { - setCellsLoading(cellsToUpdate); return; } for (FlyweightCell cell : cellsToUpdate) { GridColumn column = getColumnFromVisibleIndex(cell .getColumn()); - if (column != null) { - Object value = column.getValue(rowData); - column.getRenderer().render(cell, value); - } - } - } - - private void setCellsLoading(Iterable cellsToUpdate) { - for (FlyweightCell cell : cellsToUpdate) { - cell.getElement().setInnerText("..."); + assert column != null : "Column was not found from cell (" + + cell.getColumn() + "," + cell.getRow() + ")"; + Object value = column.getValue(rowData); + Renderer renderer = findRenderer(cell); + renderer.render(cell, value); } } - @Override - public void preAttach(Row row, Iterable cellsToAttach) { - // NOOP for now - } - - @Override - public void postAttach(Row row, - Iterable attachedCells) { - // NOOP for now - } - @Override public void preDetach(Row row, Iterable cellsToDetach) { - // NOOP for now + for (FlyweightCell cell : cellsToDetach) { + Renderer renderer = findRenderer(cell); + if (renderer instanceof WidgetRenderer) { + Widget w = Util.findWidget(cell.getElement() + .getFirstChildElement(), Widget.class); + if (w != null) { + + // Logical detach + setParent(w, null); + + // Physical detach + cell.getElement().removeChild(w.getElement()); + } + } + } } @Override @@ -1027,6 +1049,13 @@ public class Grid extends Composite implements SubPartAware { return null; } + private Renderer findRenderer(FlyweightCell cell) { + GridColumn column = getColumnFromVisibleIndex(cell.getColumn()); + assert column != null : "Could not find column at index:" + + cell.getColumn(); + return column.getRenderer(); + } + /** * Removes a column from the grid. * @@ -1735,4 +1764,17 @@ public class Grid extends Composite implements SubPartAware { private boolean isSelected(T row) { return false; } + + /** + * Accesses the package private method Widget#setParent() + * + * @param widget + * The widget to access + * @param parent + * The parent to set + */ + private static native final void setParent(Widget widget, Widget parent) + /*-{ + widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent); + }-*/; } diff --git a/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java new file mode 100644 index 0000000000..0937e8c1f2 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.renderers; + +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.Util; +import com.vaadin.client.ui.grid.FlyweightCell; + +/** + * A renderer for rendering widgets into cells. + * + * @since 7.4 + * @author Vaadin Ltd + * @param + * the row data type + * @param + * the Widget type + */ +public abstract class WidgetRenderer extends + ComplexRenderer { + + /** + * Creates a widget to attach to a cell. The widgets will be attached to the + * cell after the cell element has been attached to DOM. + * + * @return widget to attach to a cell. All returned instances should be new + * widget instances without a parent. + */ + public abstract W createWidget(); + + @Override + public void render(FlyweightCell cell, T data) { + W w = Util.findWidget(cell.getElement().getFirstChildElement(), null); + assert w != null : "Widget not found in cell (" + cell.getColumn() + + "," + cell.getRow() + ")"; + render(cell, data, w); + } + + /** + * Renders a cell with a widget. This provides a way to update any + * information in the widget that is cell specific. Do not detach the Widget + * here, it will be done automatically by the Grid when the widget is no + * longer needed. + * + * @param cell + * the cell to render + * @param data + * the data of the cell + * @param widget + * the widget embedded in the cell + */ + public abstract void render(FlyweightCell cell, T data, W widget); + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java new file mode 100644 index 0000000000..2e1a9ab4a7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -0,0 +1,94 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.openqa.selenium.Alert; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.NativeButtonElement; +import com.vaadin.testbench.elements.NativeSelectElement; +import com.vaadin.testbench.elements.ServerClass; +import com.vaadin.tests.tb3.MultiBrowserTest; +import com.vaadin.tests.widgetset.client.grid.GridClientColumnRendererConnector.Renderers; +import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers; + +/** + * Tests Grid client side renderers + * + * @since 7.4 + * @author Vaadin Ltd + */ +public class GridClientRenderers extends MultiBrowserTest { + + @Override + protected Class getUIClass() { + return GridClientColumnRenderers.class; + } + + @ServerClass("com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers.GridController") + public static class MyClientGridElement extends GridElement { + } + + @Test + public void addWidgetRenderer() throws Exception { + openTestURL(); + + // Add widget renderer column + $(NativeSelectElement.class).first().selectByText( + Renderers.WIDGET_RENDERER.toString()); + $(NativeButtonElement.class).caption("Add").first().click(); + + // Click the button in cell 1,1 + TestBenchElement cell = getGrid().getCell(1, 1); + WebElement gwtButton = cell.findElement(By.tagName("button")); + gwtButton.click(); + + // Should be an alert visible + Alert alert = driver.switchTo().alert(); + assertEquals(alert.getText(), "Click"); + } + + @Test + public void detachAndAttachGrid() { + openTestURL(); + + // Add widget renderer column + $(NativeSelectElement.class).first().selectByText( + Renderers.WIDGET_RENDERER.toString()); + $(NativeButtonElement.class).caption("Add").first().click(); + + // Detach and re-attach the Grid + $(NativeButtonElement.class).caption("DetachAttach").first().click(); + + // Click the button in cell 1,1 + TestBenchElement cell = getGrid().getCell(1, 1); + WebElement gwtButton = cell.findElement(By.tagName("button")); + gwtButton.click(); + + // Should be an alert visible + Alert alert = driver.switchTo().alert(); + assertEquals(alert.getText(), "Click"); + } + + private GridElement getGrid() { + return $(MyClientGridElement.class).first(); + } +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java new file mode 100644 index 0000000000..a4403f54fc --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -0,0 +1,186 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.client.grid; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.HasWidgets; +import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Grid; +import com.vaadin.client.ui.grid.GridColumn; +import com.vaadin.client.ui.grid.Renderer; +import com.vaadin.client.ui.grid.datasources.ListDataSource; +import com.vaadin.client.ui.grid.renderers.DateRenderer; +import com.vaadin.client.ui.grid.renderers.HtmlRenderer; +import com.vaadin.client.ui.grid.renderers.NumberRenderer; +import com.vaadin.client.ui.grid.renderers.TextRenderer; +import com.vaadin.client.ui.grid.renderers.WidgetRenderer; +import com.vaadin.shared.ui.Connect; +import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers; + +@Connect(GridClientColumnRenderers.GridController.class) +public class GridClientColumnRendererConnector extends + AbstractComponentConnector { + + public static enum Renderers { + TEXT_RENDERER, WIDGET_RENDERER, HTML_RENDERER, NUMBER_RENDERER, DATE_RENDERER; + } + + @Override + protected void init() { + Grid grid = getWidget(); + grid.setColumnHeadersVisible(false); + + // Generated some column data + List columnData = new ArrayList(); + for (int i = 0; i < 100; i++) { + columnData.add(String.valueOf(i)); + } + + // Provide data as data source + grid.setDataSource(new ListDataSource(columnData)); + + // Add a column to display the data in + grid.addColumn(createColumnWithRenderer(Renderers.TEXT_RENDERER)); + + // Handle RPC calls + registerRpc(GridClientColumnRendererRpc.class, + new GridClientColumnRendererRpc() { + + @Override + public void addColumn(Renderers renderer) { + + if (renderer == Renderers.NUMBER_RENDERER) { + getWidget().addColumn( + createNumberColumnWithRenderer(renderer)); + } else if (renderer == Renderers.DATE_RENDERER) { + getWidget().addColumn( + createDateColumnWithRenderer(renderer)); + + } else { + getWidget().addColumn( + createColumnWithRenderer(renderer)); + } + } + + @Override + public void detachAttach() { + + // Detach + HasWidgets parent = (HasWidgets) getWidget() + .getParent(); + parent.remove(getWidget()); + + // Re-attach + parent.add(getWidget()); + } + }); + } + + /** + * Creates a a renderer for a {@link Renderers} + */ + private Renderer createRenderer(Renderers renderer) { + switch (renderer) { + case TEXT_RENDERER: + return new TextRenderer(); + + case WIDGET_RENDERER: + return new WidgetRenderer() { + + @Override + public Button createWidget() { + return new Button("", new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + Window.alert("Click"); + } + }); + } + + @Override + public void render(FlyweightCell cell, String data, + Button button) { + button.setHTML(data); + } + }; + + case HTML_RENDERER: + return new HtmlRenderer() { + + @Override + public void render(FlyweightCell cell, String htmlString) { + super.render(cell, "" + htmlString + ""); + } + }; + + case NUMBER_RENDERER: + return new NumberRenderer(); + + case DATE_RENDERER: + return new DateRenderer(); + + default: + return new TextRenderer(); + } + } + + private GridColumn createColumnWithRenderer( + Renderers renderer) { + return new GridColumn(createRenderer(renderer)) { + + @Override + public String getValue(String row) { + return row; + } + }; + } + + private GridColumn createNumberColumnWithRenderer( + Renderers renderer) { + return new GridColumn(createRenderer(renderer)) { + + @Override + public Number getValue(String row) { + return Long.parseLong(row); + } + }; + } + + private GridColumn createDateColumnWithRenderer( + Renderers renderer) { + return new GridColumn(createRenderer(renderer)) { + + @Override + public Date getValue(String row) { + return new Date(); + } + }; + } + + @Override + public Grid getWidget() { + return (Grid) 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..d156bf9b88 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.client.grid; + +import com.vaadin.shared.communication.ClientRpc; +import com.vaadin.tests.widgetset.client.grid.GridClientColumnRendererConnector.Renderers; + +public interface GridClientColumnRendererRpc extends ClientRpc { + + /** + * Adds a new column with a specific renderer to the grid + * + */ + void addColumn(Renderers renderer); + + /** + * Detaches and attaches the client side Grid + */ + void detachAttach(); +} diff --git a/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java b/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java new file mode 100644 index 0000000000..e968f13ff5 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.server.grid; + +import java.util.Arrays; + +import com.vaadin.annotations.Widgetset; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.widgetset.TestingWidgetSet; +import com.vaadin.tests.widgetset.client.grid.GridClientColumnRendererConnector.Renderers; +import com.vaadin.tests.widgetset.client.grid.GridClientColumnRendererRpc; +import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.CssLayout; +import com.vaadin.ui.NativeButton; +import com.vaadin.ui.NativeSelect; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; + +@Widgetset(TestingWidgetSet.NAME) +public class GridClientColumnRenderers extends UI { + + /** + * Controls the grid on the client side + */ + public static class GridController extends AbstractComponent { + + private GridClientColumnRendererRpc rpc() { + return getRpcProxy(GridClientColumnRendererRpc.class); + } + + /** + * Adds a new column with a renderer to the grid. + */ + public void addColumn(Renderers renderer) { + rpc().addColumn(renderer); + } + + /** + * Tests detaching and attaching grid + */ + public void detachAttach() { + rpc().detachAttach(); + } + } + + @Override + protected void init(VaadinRequest request) { + final GridController controller = new GridController(); + final CssLayout controls = new CssLayout(); + final VerticalLayout content = new VerticalLayout(); + + content.addComponent(controller); + content.addComponent(controls); + setContent(content); + + final NativeSelect select = new NativeSelect( + "Add Column with Renderer", Arrays.asList(Renderers.values())); + select.setValue(Renderers.TEXT_RENDERER); + select.setNullSelectionAllowed(false); + controls.addComponent(select); + + NativeButton addColumnBtn = new NativeButton("Add"); + addColumnBtn.addClickListener(new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + Renderers renderer = (Renderers) select.getValue(); + controller.addColumn(renderer); + } + }); + controls.addComponent(addColumnBtn); + + NativeButton detachAttachBtn = new NativeButton("DetachAttach"); + detachAttachBtn.addClickListener(new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + controller.detachAttach(); + } + }); + controls.addComponent(detachAttachBtn); + } +} -- cgit v1.2.3 From c53db1fe7ee2c6993dcb38574fdeed1391658cd9 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Thu, 5 Jun 2014 09:53:44 +0300 Subject: Call ComplexRenderer.setContentVisible() from Grid body updater #13334 Change-Id: Icba9d9f3e5cdc6412c9c004356c33304024be33b --- client/src/com/vaadin/client/ui/grid/Grid.java | 238 ++++++++++++--------- .../client/ui/grid/renderers/ComplexRenderer.java | 34 ++- .../com/vaadin/shared/ui/grid/GridConstants.java | 1 - .../tests/components/grid/GridClientRenderers.java | 70 ++++++ .../grid/GridClientColumnRendererConnector.java | 86 +++++++- 5 files changed, 320 insertions(+), 109 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index ceaa63c9b6..ca3c272491 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -58,7 +58,7 @@ import com.vaadin.shared.util.SharedUtil; /** * A data grid view that supports columns and lazy loading of data rows from a * data source. - * + * *

Columns

*

* The {@link GridColumn} class defines the renderer used to render a cell in @@ -72,15 +72,15 @@ import com.vaadin.shared.util.SharedUtil; * specific column index using {@link Grid#getColumn(int)}. *

*

- * + * * TODO Explain about headers/footers once the multiple header/footer api has * been implemented - * + * *

Data sources

*

* TODO Explain about what a data source is and how it should be implemented. *

- * + * * @param * The row type of the grid. The row type is the POJO type from where * the data is retrieved into the column cells. @@ -217,6 +217,9 @@ public class Grid extends Composite implements private SelectionColumn selectionColumn; + private String rowHasDataStyleName; + private String rowSelectedStyleName; + /** * Current selection model. */ @@ -266,10 +269,10 @@ public class Grid extends Composite implements /** * Base class for grid columns internally used by the Grid. The user should * use {@link GridColumn} when creating new columns. - * + * * @param * the column type - * + * * @param * the row type */ @@ -317,7 +320,7 @@ public class Grid extends Composite implements /** * Constructs a new column with a custom renderer. - * + * * @param renderer * The renderer to use for rendering the cells */ @@ -331,7 +334,7 @@ public class Grid extends Composite implements /** * Constructs a new column with custom renderers for rows, header and * footer cells. - * + * * @param bodyRenderer * The renderer to use for rendering body cells * @param headerRenderer @@ -352,7 +355,7 @@ public class Grid extends Composite implements /** * Internally used by the grid to set itself - * + * * @param grid */ private void setGrid(Grid grid) { @@ -375,7 +378,7 @@ public class Grid extends Composite implements /** * Gets text in the header of the column. By default the header caption * is empty. - * + * * @return the text displayed in the column caption */ public String getHeaderCaption() { @@ -384,7 +387,7 @@ public class Grid extends Composite implements /** * Returns the renderer used for rendering the header cells - * + * * @return a renderer that renders header cells */ public Renderer getHeaderRenderer() { @@ -393,7 +396,7 @@ public class Grid extends Composite implements /** * Sets the renderer that renders header cells. Should not be null. - * + * * @param renderer * The renderer to use for rendering header cells. */ @@ -409,7 +412,7 @@ public class Grid extends Composite implements /** * Returns the renderer used for rendering the footer cells - * + * * @return a renderer that renders footer cells */ public Renderer getFooterRenderer() { @@ -418,7 +421,7 @@ public class Grid extends Composite implements /** * Sets the renderer that renders footer cells. Should not be null. - * + * * @param renderer * The renderer to use for rendering footer cells. */ @@ -434,7 +437,7 @@ public class Grid extends Composite implements /** * Sets the text in the header of the column. - * + * * @param caption * the text displayed in the column header */ @@ -453,7 +456,7 @@ public class Grid extends Composite implements /** * Gets text in the footer of the column. By default the footer caption * is empty. - * + * * @return The text displayed in the footer of the column */ public String getFooterCaption() { @@ -462,7 +465,7 @@ public class Grid extends Composite implements /** * Sets text in the footer of the column. - * + * * @param caption * the text displayed in the footer of the column */ @@ -480,7 +483,7 @@ public class Grid extends Composite implements /** * Is the column visible. By default all columns are visible. - * + * * @return true if the column is visible */ @Override @@ -490,7 +493,7 @@ public class Grid extends Composite implements /** * Sets a column as visible in the grid. - * + * * @param visible * true if the column should be displayed in the * grid @@ -525,10 +528,10 @@ public class Grid extends Composite implements *

* To support other types you will need to pass a custom renderer to the * column via the column constructor. - * + * * @param row * The row object that provides the cell content. - * + * * @return The cell content */ public abstract C getValue(T row); @@ -537,7 +540,7 @@ public class Grid extends Composite implements * The renderer to render the cell width. By default renders the data as * a String or adds the widget into the cell if the column type is of * widget type. - * + * * @return The renderer to render the cell content with */ public Renderer getRenderer() { @@ -546,7 +549,7 @@ public class Grid extends Composite implements /** * Finds the index of this column instance - * + * */ private int findIndexOfColumn() { return grid.findVisibleColumnIndex((GridColumn) this); @@ -555,7 +558,7 @@ public class Grid extends Composite implements /** * Sets the pixel width of the column. Use a negative value for the grid * to autosize column based on content and available space - * + * * @param pixels * the width in pixels or negative for auto sizing */ @@ -572,7 +575,7 @@ public class Grid extends Composite implements /** * Returns the pixel width of the column - * + * * @return pixel width of the column */ public int getWidth() { @@ -605,7 +608,7 @@ public class Grid extends Composite implements /** * Constructs an updater for updating a header / footer - * + * * @param rows * The row container * @param inverted @@ -618,17 +621,17 @@ public class Grid extends Composite implements /** * Gets the header/footer caption value - * + * * @param column * The column to get the value for. - * + * * @return The value that should be rendered for the column caption */ public abstract String getColumnValue(GridColumn column); /** * Gets the group caption value - * + * * @param group * The group for with the caption value should be returned * @return The value that should be rendered for the column caption @@ -637,34 +640,34 @@ public class Grid extends Composite implements /** * Is the row visible in the header/footer - * + * * @param row * the row to check - * + * * @return true if the row should be visible */ public abstract boolean isRowVisible(ColumnGroupRow row); /** * Should the first row be visible - * + * * @return true if the first row should be visible */ public abstract boolean firstRowIsVisible(); /** * The renderer that renders the cell - * + * * @param column * The column for which the cell should be rendered - * + * * @return renderer used for rendering */ public abstract Renderer getRenderer(GridColumn column); /** * The renderer that renders the cell for column groups - * + * * @param group * The group that should be rendered * @return renderer used for rendering @@ -784,12 +787,14 @@ public class Grid extends Composite implements public void setStylePrimaryName(String style) { super.setStylePrimaryName(style); escalator.setStylePrimaryName(style); + rowHasDataStyleName = getStylePrimaryName() + "-row-has-data"; + rowSelectedStyleName = getStylePrimaryName() + "-row-selected"; } /** * Creates the header updater that updates the escalator header rows from * the column and column group rows. - * + * * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createHeaderUpdater() { @@ -865,26 +870,63 @@ public class Grid extends Composite implements @Override public void update(Row row, Iterable cellsToUpdate) { int rowIndex = row.getRow(); + Element rowElement = row.getElement(); T rowData = dataSource.getRow(rowIndex); - if (rowData == null) { - return; + + boolean hasData = rowData != null; + + // Assign stylename for rows with data + boolean usedToHaveData = rowElement + .hasClassName(rowHasDataStyleName); + + if (usedToHaveData != hasData) { + setStyleName(rowElement, rowHasDataStyleName, hasData); + } + + // Assign stylename for selected rows + if (hasData) { + setStyleName(rowElement, rowSelectedStyleName, + isSelected(rowData)); + } else if (usedToHaveData) { + setStyleName(rowElement, rowSelectedStyleName, false); } for (FlyweightCell cell : cellsToUpdate) { GridColumn column = getColumnFromVisibleIndex(cell .getColumn()); + assert column != null : "Column was not found from cell (" + cell.getColumn() + "," + cell.getRow() + ")"; - Object value = column.getValue(rowData); - Renderer renderer = findRenderer(cell); - renderer.render(cell, value); - } - final String selectedClassName = getStylePrimaryName() - + "-row-selected"; + Renderer renderer = column.getRenderer(); - setStyleName(row.getElement(), selectedClassName, - isSelected(rowData)); + // Hide cell content if needed + if (renderer instanceof ComplexRenderer) { + ComplexRenderer clxRenderer = (ComplexRenderer) renderer; + if (hasData) { + if (!usedToHaveData) { + // Prepare cell for rendering + clxRenderer.setContentVisible(cell, true); + } + + Object value = column.getValue(rowData); + clxRenderer.render(cell, value); + + } else if (usedToHaveData) { + // Prepare cell for no data + clxRenderer.setContentVisible(cell, false); + } + + } else if (hasData) { + // Simple renderers just render + Object value = column.getValue(rowData); + renderer.render(cell, value); + + } else { + // Clear cell if there is no data + cell.getElement().removeAllChildren(); + } + } } @Override @@ -922,7 +964,7 @@ public class Grid extends Composite implements /** * Creates the footer updater that updates the escalator footer rows from * the column and column group rows. - * + * * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createFooterUpdater() { @@ -962,7 +1004,7 @@ public class Grid extends Composite implements /** * Refreshes header or footer rows on demand - * + * * @param rows * The row container * @param firstRowIsVisible @@ -1014,7 +1056,7 @@ public class Grid extends Composite implements /** * Adds a column as the last column in the grid. - * + * * @param column * the column to add */ @@ -1024,7 +1066,7 @@ public class Grid extends Composite implements /** * Inserts a column into a specific position in the grid. - * + * * @param index * the index where the column should be inserted into * @param column @@ -1128,7 +1170,7 @@ public class Grid extends Composite implements /** * Removes a column from the grid. - * + * * @param column * the column to remove */ @@ -1163,7 +1205,7 @@ public class Grid extends Composite implements /** * Returns the amount of columns in the grid. - * + * * @return The number of columns in the grid */ public int getColumnCount() { @@ -1172,7 +1214,7 @@ public class Grid extends Composite implements /** * Returns a list of columns in the grid. - * + * * @return A unmodifiable list of the columns in the grid */ public List> getColumns() { @@ -1182,7 +1224,7 @@ public class Grid extends Composite implements /** * Returns a column by its index in the grid. - * + * * @param index * the index of the column * @return The column in the given index @@ -1199,30 +1241,30 @@ public class Grid extends Composite implements /** * Set the column headers visible. - * + * *

* A column header is a single cell header on top of each column reserved * for a specific header for that column. The column header can be set by * {@link GridColumn#setHeaderCaption(String)} and column headers cannot be * merged with other column headers. *

- * + * *

* All column headers occupy the first header row of the grid. If you do not * wish to show the column headers in the grid you should hide the row by * setting visibility of the header row to false. *

- * + * *

* If you want to merge the column headers into groups you can use * {@link ColumnGroupRow}s to group columns together and give them a common * header. See {@link #addColumnGroupRow()} for details. *

- * + * *

* The header row is by default visible. *

- * + * * @param visible * true if header rows should be visible */ @@ -1236,7 +1278,7 @@ public class Grid extends Composite implements /** * Are the column headers visible - * + * * @return true if they are visible */ public boolean isColumnHeadersVisible() { @@ -1245,30 +1287,30 @@ public class Grid extends Composite implements /** * Set the column footers visible. - * + * *

* A column footer is a single cell footer below of each column reserved for * a specific footer for that column. The column footer can be set by * {@link GridColumn#setFooterCaption(String)} and column footers cannot be * merged with other column footers. *

- * + * *

* All column footers occupy the first footer row of the grid. If you do not * wish to show the column footers in the grid you should hide the row by * setting visibility of the footer row to false. *

- * + * *

* If you want to merge the column footers into groups you can use * {@link ColumnGroupRow}s to group columns together and give them a common * footer. See {@link #addColumnGroupRow()} for details. *

- * + * *

* The footer row is by default hidden. *

- * + * * @param visible * true if the footer row should be visible */ @@ -1282,9 +1324,9 @@ public class Grid extends Composite implements /** * Are the column footers visible - * + * * @return true if they are visible - * + * */ public boolean isColumnFootersVisible() { return columnFootersVisible; @@ -1292,15 +1334,15 @@ public class Grid extends Composite implements /** * Adds a new column group row to the grid. - * + * *

* Column group rows are rendered in the header and footer of the grid. * Column group rows are made up of column groups which groups together * columns for adding a common auxiliary header or footer for the columns. *

- * + * * Example usage: - * + * *
      * // Add a new column group row to the grid
      * ColumnGroupRow row = grid.addColumnGroupRow();
@@ -1314,7 +1356,7 @@ public class Grid extends Composite implements
      * // Set a common footer for "Column1" and "Column2"
      * column12.setFooter("Column 1&2");
      * 
- * + * * @return a column group row instance you can use to add column groups */ public ColumnGroupRow addColumnGroupRow() { @@ -1327,10 +1369,10 @@ public class Grid extends Composite implements /** * Adds a new column group row to the grid at a specific index. - * + * * @see #addColumnGroupRow() {@link Grid#addColumnGroupRow()} for example * usage - * + * * @param rowIndex * the index where the column group row should be added * @return a column group row instance you can use to add column groups @@ -1345,7 +1387,7 @@ public class Grid extends Composite implements /** * Removes a column group row - * + * * @param row * The row to remove */ @@ -1357,9 +1399,9 @@ public class Grid extends Composite implements /** * Get the column group rows - * + * * @return a unmodifiable list of column group rows - * + * */ public List> getColumnGroupRows() { return Collections.unmodifiableList(new ArrayList>( @@ -1368,7 +1410,7 @@ public class Grid extends Composite implements /** * Returns the column group for a row and column - * + * * @param row * The row of the column * @param column @@ -1392,7 +1434,7 @@ public class Grid extends Composite implements *

* Note: This method will change the widget's size in the browser * only if {@link #getHeightMode()} returns {@link HeightMode#CSS}. - * + * * @see #setHeightMode(HeightMode) */ @Override @@ -1407,7 +1449,7 @@ public class Grid extends Composite implements /** * Sets the data source used by this grid. - * + * * @param dataSource * the data source to use, not null * @throws IllegalArgumentException @@ -1460,7 +1502,7 @@ public class Grid extends Composite implements *

* All columns up to and including the given column will be frozen in place * when the grid is scrolled sideways. - * + * * @param lastFrozenColumn * the rightmost column to freeze, or null to not * have any columns frozen @@ -1493,7 +1535,7 @@ public class Grid extends Composite implements * Note: Most usually, this method returns the very value set with * {@link #setLastFrozenColumn(GridColumn)}. This value, however, can be * reset to null if the column is removed from this grid. - * + * * @return the rightmost frozen column in the grid, or null if * no columns are frozen. */ @@ -1513,7 +1555,7 @@ public class Grid extends Composite implements /** * Scrolls to a certain row, using {@link ScrollDestination#ANY}. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @throws IllegalArgumentException @@ -1527,7 +1569,7 @@ public class Grid extends Composite implements /** * Scrolls to a certain row, using user-specified scroll destination. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @param destination @@ -1546,7 +1588,7 @@ public class Grid extends Composite implements /** * Scrolls to a certain row using only user-specified parameters. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @param destination @@ -1603,7 +1645,7 @@ public class Grid extends Composite implements *

* If Grid is currently not in {@link HeightMode#ROW}, the given value is * remembered, and applied once the mode is applied. - * + * * @param rows * The height in terms of number of rows displayed in Grid's * body. If Grid doesn't contain enough rows, white space is @@ -1615,7 +1657,7 @@ public class Grid extends Composite implements * infinite} * @throws IllegalArgumentException * if {@code rows} is {@link Double#isNaN(double) NaN} - * + * * @see #setHeightMode(HeightMode) */ public void setHeightByRows(double rows) throws IllegalArgumentException { @@ -1627,7 +1669,7 @@ public class Grid extends Composite implements * {@link #getHeightMode()} is {@link HeightMode#ROW}. *

* By default, it is {@value Escalator#DEFAULT_HEIGHT_BY_ROWS}. - * + * * @return the amount of rows that should be shown in Grid's body, while in * {@link HeightMode#ROW}. * @see #setHeightByRows(double) @@ -1647,7 +1689,7 @@ public class Grid extends Composite implements * Note: If headers/footers are inserted or removed, the widget * will resize itself to still display the required amount of rows in its * body. It also takes the horizontal scrollbar into account. - * + * * @param heightMode * the mode in to which Grid should be set */ @@ -1669,7 +1711,7 @@ public class Grid extends Composite implements * Returns the current {@link HeightMode} the Grid is in. *

* Defaults to {@link HeightMode#CSS}. - * + * * @return the current HeightMode */ public HeightMode getHeightMode() { @@ -1832,7 +1874,7 @@ public class Grid extends Composite implements /** * Accesses the package private method Widget#setParent() - * + * * @param widget * The widget to access * @param parent @@ -1845,7 +1887,7 @@ public class Grid extends Composite implements /** * Sets the current selection model. - * + * * @param selectionModel * a selection model implementation. * @throws IllegalArgumentException @@ -1863,7 +1905,7 @@ public class Grid extends Composite implements /** * Gets a reference to the current selection model. - * + * * @return the currently used SelectionModel instance. */ public SelectionModel getSelectionModel() { @@ -1874,7 +1916,7 @@ public class Grid extends Composite implements * Sets current selection mode. *

* This is a shorthand method for {@link Grid#setSelectionModel}. - * + * * @param mode * a selection mode value * @see {@link SelectionMode}. @@ -1886,7 +1928,7 @@ public class Grid extends Composite implements /** * Test if a row is selected. - * + * * @param row * a row object * @return true, if the current selection model considers the provided row @@ -1902,7 +1944,7 @@ public class Grid extends Composite implements * Only selection models implementing {@link SelectionModel.Single} and * {@link SelectionModel.Multi} are supported; for anything else, an * exception will be thrown. - * + * * @param row * a row object * @return true iff the current selection changed @@ -1927,7 +1969,7 @@ public class Grid extends Composite implements * Only selection models implementing {@link SelectionModel.Single} and * {@link SelectionModel.Multi} are supported; for anything else, an * exception will be thrown. - * + * * @param row * a row object * @return true iff the current selection changed @@ -1952,7 +1994,7 @@ public class Grid extends Composite implements * Only selection models implementing {@link SelectionModel.Single} are * valid for this method; for anything else, use the * {@link Grid#getSelectedRows()} method. - * + * * @return a selected row reference, or null, if no row is selected * @throws IllegalStateException * if the current selection model is not an instance of @@ -1969,7 +2011,7 @@ public class Grid extends Composite implements /** * Gets currently selected rows from the current selection model. - * + * * @return a non-null collection containing all currently selected rows. */ public Collection getSelectedRows() { diff --git a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java index cf3e43c88a..289f3809be 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java @@ -17,7 +17,10 @@ package com.vaadin.client.ui.grid.renderers; import java.util.Collection; +import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.Style.Visibility; import com.vaadin.client.ui.grid.Cell; import com.vaadin.client.ui.grid.FlyweightCell; import com.vaadin.client.ui.grid.Renderer; @@ -96,18 +99,33 @@ public abstract class ComplexRenderer implements Renderer { } /** - * Hides content by setting visibility: hidden to all elements inside the - * cell. Text nodes are left as is for now - renderers that add such to the - * root element need to implement explicit support hiding them + * Used by Grid to toggle whether to show actual data or just an empty + * placeholder while data is loading. This method is invoked whenever a cell + * changes between data being available and data missing. + *

+ * Default implementation hides content by setting visibility: hidden to all + * elements inside the cell. Text nodes are left as is - renderers that add + * such to the root element need to implement explicit support hiding them. * * @param cell * The cell - * @param visible - * Is the cell content be visible - * @return true if the content should be set visible + * @param hasData + * Has the cell content been loaded from the data source + * */ - public boolean setContentVisible(FlyweightCell cell, boolean visible) { - return false; + public void setContentVisible(FlyweightCell cell, boolean hasData) { + Element cellElement = cell.getElement(); + for (int n = 0; n < cellElement.getChildCount(); n++) { + Node node = cellElement.getChild(n); + if (Element.is(node)) { + Element e = Element.as(node); + if (hasData) { + e.getStyle().clearVisibility(); + } else { + e.getStyle().setVisibility(Visibility.HIDDEN); + } + } + } } /** diff --git a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java index d5fdd40120..8b264bf426 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java @@ -31,5 +31,4 @@ public final class GridConstants implements Serializable { * explicitly defined padding value. */ public static final int DEFAULT_PADDING = 0; - } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index 2e1a9ab4a7..2f14ccf3f3 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -16,6 +16,7 @@ package com.vaadin.tests.components.grid; import static org.junit.Assert.assertEquals; +import junit.framework.Assert; import org.junit.Test; import org.openqa.selenium.Alert; @@ -38,15 +39,31 @@ import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers; */ public class GridClientRenderers extends MultiBrowserTest { + private int latency = 0; + @Override protected Class getUIClass() { return GridClientColumnRenderers.class; } + @Override + protected String getDeploymentPath() { + if (latency > 0) { + return super.getDeploymentPath() + "?latency=" + latency; + } + return super.getDeploymentPath(); + } + @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(); @@ -88,7 +105,60 @@ public class GridClientRenderers extends MultiBrowserTest { assertEquals(alert.getText(), "Click"); } + @Test + public void rowsWithDataHasStyleName() throws Exception { + + // Simulate network latency with 1000ms + latency = 1000; + + openTestURL(); + + TestBenchElement row = getGrid().getRow(1); + String className = row.getAttribute("class"); + Assert.assertFalse(className.contains("v-grid-row-has-data")); + + // Wait for data to arrive + sleep(3000); + + row = getGrid().getRow(1); + className = row.getAttribute("class"); + Assert.assertTrue(className.contains("v-grid-row-has-data")); + } + + @Test + public void complexRendererSetVisibleContent() throws Exception { + + // Simulate network latency with 1000ms + latency = 1000; + + openTestURL(); + + addColumn(Renderers.CPLX_RENDERER); + + // Fetch data + getGrid().scrollToRow(50); + + // Cell should be red (setContentVisible set cell red) + String backgroundColor = getGrid().getCell(1, 1).getCssValue( + "backgroundColor"); + assertEquals("rgba(255, 0, 0, 1)", backgroundColor); + + // Wait for data to arrive + sleep(3000); + + // Cell should no longer be red + backgroundColor = getGrid().getCell(1, 1) + .getCssValue("backgroundColor"); + assertEquals("rgba(255, 255, 255, 1)", backgroundColor); + } + 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/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index a4403f54fc..e4d8042605 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -21,15 +21,20 @@ import java.util.List; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; +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.FlyweightCell; import com.vaadin.client.ui.grid.Grid; import com.vaadin.client.ui.grid.GridColumn; import com.vaadin.client.ui.grid.Renderer; import com.vaadin.client.ui.grid.datasources.ListDataSource; +import com.vaadin.client.ui.grid.renderers.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; @@ -43,7 +48,57 @@ public class GridClientColumnRendererConnector extends AbstractComponentConnector { public static enum Renderers { - TEXT_RENDERER, WIDGET_RENDERER, HTML_RENDERER, NUMBER_RENDERER, DATE_RENDERER; + TEXT_RENDERER, WIDGET_RENDERER, HTML_RENDERER, NUMBER_RENDERER, DATE_RENDERER, CPLX_RENDERER; + } + + /** + * Datasource for simulating network latency + */ + private class DelayedDataSource implements DataSource { + + private DataSource ds; + private int firstRowIndex; + private int numberOfRows; + private DataChangeHandler dataChangeHandler; + private int latency; + + public DelayedDataSource(DataSource 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); + } + }.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 @@ -58,7 +113,13 @@ public class GridClientColumnRendererConnector extends } // Provide data as data source - grid.setDataSource(new ListDataSource(columnData)); + if (Location.getParameter("latency") != null) { + grid.setDataSource(new DelayedDataSource( + new ListDataSource(columnData), Integer + .parseInt(Location.getParameter("latency")))); + } else { + grid.setDataSource(new ListDataSource(columnData)); + } // Add a column to display the data in grid.addColumn(createColumnWithRenderer(Renderers.TEXT_RENDERER)); @@ -141,6 +202,27 @@ public class GridClientColumnRendererConnector extends case DATE_RENDERER: return new DateRenderer(); + case CPLX_RENDERER: + return new ComplexRenderer() { + + @Override + public void render(FlyweightCell cell, String data) { + cell.getElement().setInnerHTML("" + data + ""); + 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); + } + }; + default: return new TextRenderer(); } -- cgit v1.2.3 From 3de730040c3b092cee2e273d09d370087172c70e Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Mon, 16 Jun 2014 12:33:21 +0300 Subject: Implements RowHandle (#13334) Change-Id: Ifa33094843986f95ff831fee9b61fddf81df8f3a --- .../client/data/AbstractRemoteDataSource.java | 140 +++++++++++++++++++++ client/src/com/vaadin/client/data/DataSource.java | 109 ++++++++++++++++ .../vaadin/client/data/RpcDataSourceConnector.java | 9 ++ .../client/ui/grid/datasources/ListDataSource.java | 62 +++++++++ .../grid/GridClientColumnRendererConnector.java | 6 + 5 files changed, 326 insertions(+) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java index 6edb73b4df..2395dc848c 100644 --- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java +++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java @@ -18,6 +18,7 @@ package com.vaadin.client.data; import java.util.HashMap; import java.util.List; +import java.util.Map; import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.Scheduler; @@ -41,6 +42,88 @@ import com.vaadin.shared.ui.grid.Range; */ public abstract class AbstractRemoteDataSource implements DataSource { + private class RowHandleImpl extends RowHandle { + private T row; + private final Object key; + + public RowHandleImpl(final T row, final Object key) { + this.row = row; + this.key = key; + } + + /** + * A method for the data source to update the row data. + * + * @param row + * the updated row object + */ + public void setRow(final T row) { + this.row = row; + assert getRowKey(row).equals(key) : "The old key does not " + + "equal the new key for the given row (old: " + key + + ", new :" + getRowKey(row) + ")"; + } + + @Override + public T getRow() throws IllegalStateException { + if (isPinned()) { + return row; + } else { + throw new IllegalStateException("The row handle for key " + key + + " was not pinned"); + } + } + + private boolean isPinned() { + return pinnedRows.containsKey(key); + } + + @Override + public void pin() { + Integer count = pinnedCounts.get(key); + if (count == null) { + count = Integer.valueOf(0); + pinnedRows.put(key, this); + } + pinnedCounts.put(key, Integer.valueOf(count.intValue() + 1)); + } + + @Override + public void unpin() throws IllegalStateException { + final Integer count = pinnedCounts.get(key); + if (count == null) { + throw new IllegalStateException("Row " + row + " with key " + + key + " was not pinned to begin with"); + } else if (count.equals(Integer.valueOf(1))) { + pinnedRows.remove(key); + pinnedCounts.remove(key); + } else { + pinnedCounts.put(key, Integer.valueOf(count.intValue() - 1)); + } + } + + @Override + protected boolean equalsExplicit(final Object obj) { + if (obj instanceof AbstractRemoteDataSource.RowHandleImpl) { + /* + * Java prefers AbstractRemoteDataSource.RowHandleImpl. I + * like the @SuppressWarnings more (keeps the line length in + * check.) + */ + @SuppressWarnings("unchecked") + final RowHandleImpl rhi = (RowHandleImpl) obj; + return key.equals(rhi.key); + } else { + return false; + } + } + + @Override + protected int hashCodeExplicit() { + return key.hashCode(); + } + } + /** * Records the start of the previously requested range. This is used when * tracking request timings to distinguish between explicit responses and @@ -71,6 +154,9 @@ public abstract class AbstractRemoteDataSource implements DataSource { } }; + private Map pinnedCounts = new HashMap(); + private Map pinnedRows = new HashMap(); + /** * Sets the estimated number of rows in the data source. * @@ -243,6 +329,8 @@ public abstract class AbstractRemoteDataSource implements DataSource { cached = newUsefulData; } } + + updatePinnedRows(rowData); } if (!partition[0].isEmpty() || !partition[2].isEmpty()) { @@ -261,6 +349,16 @@ public abstract class AbstractRemoteDataSource implements DataSource { Profiler.leave("AbstractRemoteDataSource.setRowData"); } + private void updatePinnedRows(final List rowData) { + for (final T row : rowData) { + final Object key = getRowKey(row); + final RowHandleImpl handle = pinnedRows.get(key); + if (handle != null) { + handle.setRow(row); + } + } + } + /** * Informs this data source that the server has removed data. * @@ -391,4 +489,46 @@ public abstract class AbstractRemoteDataSource implements DataSource { return maxCacheRange; } + + @Override + public RowHandle getHandle(T row) throws IllegalStateException { + Object key = getRowKey(row); + + if (key == null) { + throw new NullPointerException("key may not be null (row: " + row + + ")"); + } + + if (pinnedRows.containsKey(key)) { + return pinnedRows.get(key); + } else if (rowCache.containsValue(row)) { + return new RowHandleImpl(row, key); + } else { + throw new IllegalStateException("The cache of this DataSource " + + "does not currently contain the row " + row); + } + } + + /** + * Gets a stable key for the row object. + *

+ * This method is a workaround for the fact that there is no means to force + * proper implementations for {@link #hashCode()} and + * {@link #equals(Object)} methods. + *

+ * Since the same row object will be created several times for the same + * logical data, the DataSource needs a mechanism to be able to compare two + * objects, and figure out whether or not they represent the same data. Even + * if all the fields of an entity would be changed, it still could represent + * the very same thing (say, a person changes all of her names.) + *

+ * A very usual and simple example what this could be, is an unique ID for + * this object that would also be stored in a database. + * + * @param row + * the row object for which to get the key + * @return a non-null object that uniquely and consistently represents the + * row object + */ + abstract public Object getRowKey(T row); } diff --git a/client/src/com/vaadin/client/data/DataSource.java b/client/src/com/vaadin/client/data/DataSource.java index 8620cb2de5..695a2a7c2f 100644 --- a/client/src/com/vaadin/client/data/DataSource.java +++ b/client/src/com/vaadin/client/data/DataSource.java @@ -27,6 +27,104 @@ package com.vaadin.client.data; * the row type */ public interface DataSource { + + /** + * A handle that contains information on whether a row should be + * {@link #pin() pinned} or {@link #unpin() unpinned}, and also always the + * most recent representation for that particular row. + * + * @param + * the row type + */ + public abstract class RowHandle { + /** + * Gets the most recent representation for the row this handle + * represents. + * + * @return the most recent representation for the row this handle + * represents + * @throws IllegalStateException + * if this row handle isn't currently pinned + * @see #pin() + */ + public abstract T getRow() throws IllegalStateException; + + /** + * Marks this row as pinned. + *

+ * Note: Pinning a row multiple times requires an equal amount + * of unpins to free the row from the "pinned" status. + *

+ * Technical Note: Pinning a row makes sure that the row object + * for a particular set of data is always kept as up to date as the data + * source is able to. Since the DataSource might create a new instance + * of an object, object references aren't necessarily kept up-to-date. + * This is a technical work-around for that. + * + * @see #unpin() + */ + public abstract void pin(); + + /** + * Marks this row as unpinned. + *

+ * Note: Pinning a row multiple times requires an equal amount + * of unpins to free the row from the "pinned" status. + *

+ * Technical Note: Pinning a row makes sure that the row object + * for a particular set of data is always kept as up to date as the data + * source is able to. Since the DataSource might create a new instance + * of an object, object references aren't necessarily kept up-to-date. + * This is a technical work-around for that. + * + * @throws IllegalStateException + * if this row handle has not been pinned before + * @see #pin() + */ + public abstract void unpin() throws IllegalStateException; + + /** + * An explicit override for {@link Object#equals(Object)}. This method + * should be functionally equivalent to a properly implemented equals + * method. + *

+ * Having a properly implemented equals method is imperative for + * RowHandle to function. Because Java has no mechanism to force an + * override of an existing method, we're defining a new method for that + * instead. + * + * @param rowHandle + * the reference object with which to compare + * @return {@code true} if this object is the same as the obj argument; + * {@code false} otherwise. + */ + protected abstract boolean equalsExplicit(Object obj); + + /** + * An explicit override for {@link Object#hashCode()}. This method + * should be functionally equivalent to a properly implemented hashCode + * method. + *

+ * Having a properly implemented hashCode method is imperative for + * RowHandle to function. Because Java has no mechanism to force an + * override of an existing method, we're defining a new method for that + * instead. + * + * @return a hash code value for this object + */ + protected abstract int hashCodeExplicit(); + + @Override + public int hashCode() { + return hashCodeExplicit(); + } + + @Override + public boolean equals(Object obj) { + return equalsExplicit(obj); + } + } + /** * Informs the data source that data for the given range is needed. A data * source only has one active region at a time, so calling this method @@ -73,4 +171,15 @@ public interface DataSource { */ public void setDataChangeHandler(DataChangeHandler dataChangeHandler); + /** + * Gets a {@link RowHandle} of a row object in the cache. + * + * @param row + * the row object for which to retrieve a row handle + * @return a non-null row handle of the given row object + * @throw IllegalStateException if this data source cannot be sure whether + * or not the given row exists. In practice this usually + * means that the row is not currently in this data source's cache. + */ + public RowHandle getHandle(T row); } diff --git a/client/src/com/vaadin/client/data/RpcDataSourceConnector.java b/client/src/com/vaadin/client/data/RpcDataSourceConnector.java index e07d2297c9..fba8c732f6 100644 --- a/client/src/com/vaadin/client/data/RpcDataSourceConnector.java +++ b/client/src/com/vaadin/client/data/RpcDataSourceConnector.java @@ -47,6 +47,15 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { getRpcProxy(DataRequestRpc.class).requestRows(firstRowIndex, numberOfRows, cached.getStart(), cached.length()); } + + @Override + public Object getRowKey(String[] row) { + /* + * FIXME will be properly implemented by another patch (Henrik Paul: + * 16.6.2014) + */ + return row; + } }; @Override diff --git a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java index 90d12d97d1..94c32bfb33 100644 --- a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java +++ b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java @@ -24,6 +24,7 @@ import java.util.ListIterator; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; +import com.vaadin.shared.util.SharedUtil; /** * A simple list based on an in-memory data source for simply adding a list of @@ -51,6 +52,59 @@ import com.vaadin.client.data.DataSource; */ public class ListDataSource implements DataSource { + private class RowHandleImpl extends RowHandle { + + private final T row; + + public RowHandleImpl(T row) { + this.row = row; + } + + @Override + public T getRow() { + /* + * We'll cheat here and don't throw an IllegalStateException even if + * this isn't pinned, because we know that the reference never gets + * stale. + */ + return row; + } + + @Override + public void pin() { + // NOOP, really + } + + @Override + public void unpin() throws IllegalStateException { + /* + * Just to make things easier for everyone, we won't throw the + * exception, even in illegal situations. + */ + } + + @Override + protected boolean equalsExplicit(Object obj) { + if (obj instanceof ListDataSource.RowHandleImpl) { + /* + * Java prefers AbstractRemoteDataSource.RowHandleImpl. I + * like the @SuppressWarnings more (keeps the line length in + * check.) + */ + @SuppressWarnings("unchecked") + RowHandleImpl rhi = (RowHandleImpl) obj; + return SharedUtil.equals(row, rhi.row); + } else { + return false; + } + } + + @Override + protected int hashCodeExplicit() { + return row.hashCode(); + } + } + /** * Wraps the datasource list and notifies the change handler of changing to * the list @@ -83,6 +137,7 @@ public class ListDataSource implements DataSource { } @Override + @SuppressWarnings("hiding") public T[] toArray(T[] a) { return toArray(a); } @@ -354,4 +409,11 @@ public class ListDataSource implements DataSource { public List asList() { return wrapper; } + + @Override + public RowHandle getHandle(T row) throws IllegalStateException { + assert ds.contains(row) : "This data source doesn't contain the row " + + row; + return new RowHandleImpl(row); + } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index e4d8042605..37b2f926e4 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -99,6 +99,12 @@ public class GridClientColumnRendererConnector extends public void setDataChangeHandler(DataChangeHandler dataChangeHandler) { this.dataChangeHandler = dataChangeHandler; } + + @Override + public RowHandle getHandle(String row) { + // TODO Auto-generated method stub (henrik paul: 17.6.) + return null; + } } @Override -- cgit v1.2.3 From 79174319aa336c0200d516cc473321d7b04fc921 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 18 Jun 2014 13:58:19 +0300 Subject: Make GridClientRenderers test stable Change-Id: I65ca00efa405b3ac97c45dc14302ca892e105c4f --- .../tests/components/grid/GridClientRenderers.java | 62 +++++++++++++++------- 1 file changed, 43 insertions(+), 19 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index 2f14ccf3f3..2e8cb433d3 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -16,11 +16,15 @@ package com.vaadin.tests.components.grid; import static org.junit.Assert.assertEquals; -import junit.framework.Assert; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.List; import org.junit.Test; import org.openqa.selenium.Alert; import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.By; import com.vaadin.testbench.TestBenchElement; @@ -41,6 +45,14 @@ public class GridClientRenderers extends MultiBrowserTest { private int latency = 0; + @Override + public List getBrowsersToTest() { + List browsers = super.getBrowsersToTest(); + // FIXME: PhantomJS can't handle alerts. Fix test to use something else. + browsers.remove(Browser.PHANTOMJS.getDesiredCapabilities()); + return browsers; + } + @Override protected Class getUIClass() { return GridClientColumnRenderers.class; @@ -80,7 +92,8 @@ public class GridClientRenderers extends MultiBrowserTest { // Should be an alert visible Alert alert = driver.switchTo().alert(); - assertEquals(alert.getText(), "Click"); + assertEquals("Alert window did not contain text \"Click\"", + alert.getText(), "Click"); } @Test @@ -102,54 +115,65 @@ public class GridClientRenderers extends MultiBrowserTest { // Should be an alert visible Alert alert = driver.switchTo().alert(); - assertEquals(alert.getText(), "Click"); + assertEquals("Alert window did not contain text \"Click\"", + alert.getText(), "Click"); } @Test public void rowsWithDataHasStyleName() throws Exception { - // Simulate network latency with 1000ms - latency = 1000; + // Simulate network latency with 1500ms unless it's IE. IE takes longer + // time to get started. + latency = (BrowserUtil.isIE(getDesiredCapabilities()) ? 4000 : 1500); openTestURL(); TestBenchElement row = getGrid().getRow(1); String className = row.getAttribute("class"); - Assert.assertFalse(className.contains("v-grid-row-has-data")); + 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(3000); + sleep(latency + 1000); row = getGrid().getRow(1); className = row.getAttribute("class"); - Assert.assertTrue(className.contains("v-grid-row-has-data")); + 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 { - // Simulate network latency with 1000ms - latency = 1000; + // Simulate network latency with 1500ms + latency = 1500; + + // Chrome uses RGB instead of RGBA + String colorRed = "rgba(255, 0, 0, 1)"; + String colorWhite = "rgba(255, 255, 255, 1)"; + if (BrowserUtil.isChrome(getDesiredCapabilities())) { + colorRed = "rgb(255, 0, 0)"; + colorWhite = "rgb(255, 255, 255)"; + } openTestURL(); addColumn(Renderers.CPLX_RENDERER); - // Fetch data - getGrid().scrollToRow(50); - // Cell should be red (setContentVisible set cell red) - String backgroundColor = getGrid().getCell(1, 1).getCssValue( + String backgroundColor = getGrid().getCell(51, 1).getCssValue( "backgroundColor"); - assertEquals("rgba(255, 0, 0, 1)", backgroundColor); + assertEquals("Background color was not red.", colorRed, backgroundColor); // Wait for data to arrive - sleep(3000); + sleep(latency + 1000); // Cell should no longer be red - backgroundColor = getGrid().getCell(1, 1) - .getCssValue("backgroundColor"); - assertEquals("rgba(255, 255, 255, 1)", backgroundColor); + backgroundColor = getGrid().getCell(51, 1).getCssValue( + "backgroundColor"); + assertEquals("Background color was not white", colorWhite, + backgroundColor); } private GridElement getGrid() { -- cgit v1.2.3 From 254a9e2c962e921bdb6217e49cd898a8a2a50bc8 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Wed, 18 Jun 2014 14:33:18 +0300 Subject: Don't use alerts in GridClientRenderers test Change-Id: I892a41b344dfc200ca6a2240bf16e4b2935d1550 --- .../tests/components/grid/GridClientRenderers.java | 31 ++++++---------------- .../grid/GridClientColumnRendererConnector.java | 7 ++--- 2 files changed, 12 insertions(+), 26 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index 2e8cb433d3..15bd323e08 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -19,12 +19,8 @@ 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.Alert; import org.openqa.selenium.WebElement; -import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.By; import com.vaadin.testbench.TestBenchElement; @@ -45,14 +41,6 @@ public class GridClientRenderers extends MultiBrowserTest { private int latency = 0; - @Override - public List getBrowsersToTest() { - List browsers = super.getBrowsersToTest(); - // FIXME: PhantomJS can't handle alerts. Fix test to use something else. - browsers.remove(Browser.PHANTOMJS.getDesiredCapabilities()); - return browsers; - } - @Override protected Class getUIClass() { return GridClientColumnRenderers.class; @@ -91,9 +79,8 @@ public class GridClientRenderers extends MultiBrowserTest { gwtButton.click(); // Should be an alert visible - Alert alert = driver.switchTo().alert(); - assertEquals("Alert window did not contain text \"Click\"", - alert.getText(), "Click"); + assertEquals("Button did not contain text \"Clicked\"", + gwtButton.getText(), "Clicked"); } @Test @@ -114,17 +101,15 @@ public class GridClientRenderers extends MultiBrowserTest { gwtButton.click(); // Should be an alert visible - Alert alert = driver.switchTo().alert(); - assertEquals("Alert window did not contain text \"Click\"", - alert.getText(), "Click"); + assertEquals("Button did not contain text \"Clicked\"", + gwtButton.getText(), "Clicked"); } @Test public void rowsWithDataHasStyleName() throws Exception { - // Simulate network latency with 1500ms unless it's IE. IE takes longer - // time to get started. - latency = (BrowserUtil.isIE(getDesiredCapabilities()) ? 4000 : 1500); + // Simulate network latency with 4000ms + latency = 4000; openTestURL(); @@ -146,8 +131,8 @@ public class GridClientRenderers extends MultiBrowserTest { @Test public void complexRendererSetVisibleContent() throws Exception { - // Simulate network latency with 1500ms - latency = 1500; + // Simulate network latency with 2000ms + latency = 2000; // Chrome uses RGB instead of RGBA String colorRed = "rgba(255, 0, 0, 1)"; diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index 37b2f926e4..24e79d775f 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -22,7 +22,6 @@ import java.util.List; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.Timer; -import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.Location; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HasWidgets; @@ -177,13 +176,15 @@ public class GridClientColumnRendererConnector extends @Override public Button createWidget() { - return new Button("", new ClickHandler() { + final Button button = new Button(""); + button.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - Window.alert("Click"); + button.setText("Clicked"); } }); + return button; } @Override -- cgit v1.2.3 From f4a538019bc6c5abeeb453d9f116088d03d7c32f Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Wed, 18 Jun 2014 16:04:46 +0300 Subject: Change row data type from String[] to String (#13334) Instead of having the data type as one-string-per-column, we now have the entire row encoded as JSON Change-Id: I709b2daa88c516d98203ef463b57257a6647bacd --- .../vaadin/client/data/RpcDataSourceConnector.java | 27 +++++- .../com/vaadin/client/ui/grid/GridConnector.java | 50 ++++++---- .../grid/renderers/AbstractRendererConnector.java | 2 - .../com/vaadin/data/RpcDataProviderExtension.java | 107 +++++++++++++++------ .../com/vaadin/shared/data/DataProviderRpc.java | 22 ++++- .../src/com/vaadin/shared/ui/grid/GridState.java | 7 ++ .../tests/components/grid/CustomRenderer.java | 60 ++++++++++++ .../tests/components/grid/CustomRendererTest.java | 42 ++++++++ .../tests/components/grid/IntArrayRenderer.java | 36 +++++++ .../client/grid/IntArrayRendererConnector.java | 51 ++++++++++ 10 files changed, 344 insertions(+), 60 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/data/RpcDataSourceConnector.java b/client/src/com/vaadin/client/data/RpcDataSourceConnector.java index fba8c732f6..2b9bf5c90e 100644 --- a/client/src/com/vaadin/client/data/RpcDataSourceConnector.java +++ b/client/src/com/vaadin/client/data/RpcDataSourceConnector.java @@ -16,8 +16,12 @@ package com.vaadin.client.data; -import java.util.List; +import java.util.ArrayList; +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONParser; +import com.google.gwt.json.client.JSONValue; import com.vaadin.client.ServerConnector; import com.vaadin.client.extensions.AbstractExtensionConnector; import com.vaadin.client.ui.grid.GridConnector; @@ -39,7 +43,7 @@ import com.vaadin.shared.ui.grid.Range; @Connect(com.vaadin.data.RpcDataProviderExtension.class) public class RpcDataSourceConnector extends AbstractExtensionConnector { - private final AbstractRemoteDataSource dataSource = new AbstractRemoteDataSource() { + private final AbstractRemoteDataSource dataSource = new AbstractRemoteDataSource() { @Override protected void requestRows(int firstRowIndex, int numberOfRows) { Range cached = getCachedRange(); @@ -49,7 +53,7 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { } @Override - public Object getRowKey(String[] row) { + public Object getRowKey(JSONObject row) { /* * FIXME will be properly implemented by another patch (Henrik Paul: * 16.6.2014) @@ -65,7 +69,22 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { registerRpc(DataProviderRpc.class, new DataProviderRpc() { @Override - public void setRowData(int firstRow, List rows) { + public void setRowData(int firstRow, String rowsJson) { + JSONValue parsedJson = JSONParser.parseStrict(rowsJson); + JSONArray rowArray = parsedJson.isArray(); + assert rowArray != null : "Was unable to parse JSON into an array: " + + parsedJson; + + ArrayList rows = new ArrayList(rowArray + .size()); + for (int i = 0; i < rowArray.size(); i++) { + JSONValue rowValue = rowArray.get(i); + JSONObject rowObject = rowValue.isObject(); + assert rowObject != null : "Was unable to parse JSON into an object: " + + rowValue; + rows.add(rowObject); + } + dataSource.setRowData(firstRow, rows); } diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index ab304a9214..95b493b451 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -24,6 +24,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONValue; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; @@ -38,6 +41,10 @@ import com.vaadin.shared.ui.grid.ScrollDestination; /** * Connects the client side {@link Grid} widget with the server side * {@link com.vaadin.ui.components.grid.Grid} component. + *

+ * The Grid is typed to JSONObject. The structure of the JSONObject is described + * at {@link com.vaadin.shared.data.DataProviderRpc#setRowData(int, List) + * DataProviderRpc.setRowData(int, List)}. * * @since 7.4 * @author Vaadin Ltd @@ -49,23 +56,29 @@ public class GridConnector extends AbstractComponentConnector { * Custom implementation of the custom grid column using a String[] to * represent the cell value and String as a column type. */ - private class CustomGridColumn extends GridColumn { + private class CustomGridColumn extends GridColumn { private final String id; - private AbstractRendererConnector rendererConnector; + private AbstractRendererConnector rendererConnector; public CustomGridColumn(String id, - AbstractRendererConnector rendererConnector) { + AbstractRendererConnector rendererConnector) { super(rendererConnector.getRenderer()); this.rendererConnector = rendererConnector; this.id = id; } @Override - public String getValue(String[] obj) { - // TODO this should invoke AbstractRendererConnector.decode - return obj[resolveCurrentIndexFromState()]; + public Object getValue(final JSONObject obj) { + final JSONValue rowData = obj.get(GridState.JSONKEY_DATA); + final JSONArray rowDataArray = rowData.isArray(); + assert rowDataArray != null : "Was unable to parse JSON into an array: " + + rowData; + + final int columnIndex = resolveCurrentIndexFromState(); + final JSONValue columnValue = rowDataArray.get(columnIndex); + return rendererConnector.decode(columnValue); } /* @@ -74,7 +87,7 @@ public class GridConnector extends AbstractComponentConnector { * * TODO remove once support for changing renderers is implemented */ - private AbstractRendererConnector getRendererConnector() { + private AbstractRendererConnector getRendererConnector() { return rendererConnector; } @@ -97,8 +110,8 @@ public class GridConnector extends AbstractComponentConnector { @Override @SuppressWarnings("unchecked") - public Grid getWidget() { - return (Grid) super.getWidget(); + public Grid getWidget() { + return (Grid) super.getWidget(); } @Override @@ -207,7 +220,7 @@ public class GridConnector extends AbstractComponentConnector { * The index of the column to update */ private void updateColumnFromStateChangeEvent(int columnIndex) { - GridColumn column = getWidget().getColumn(columnIndex); + GridColumn column = getWidget().getColumn(columnIndex); GridColumnState columnState = getState().columns.get(columnIndex); updateColumnFromState(column, columnState); @@ -226,8 +239,9 @@ public class GridConnector extends AbstractComponentConnector { */ private void addColumnFromStateChangeEvent(int columnIndex) { GridColumnState state = getState().columns.get(columnIndex); + @SuppressWarnings("unchecked") CustomGridColumn column = new CustomGridColumn(state.id, - ((AbstractRendererConnector) state.rendererConnector)); + ((AbstractRendererConnector) state.rendererConnector)); columnIdToColumn.put(state.id, column); // Adds a column to grid, and registers Grid with the column. @@ -252,7 +266,7 @@ public class GridConnector extends AbstractComponentConnector { * @param state * The state to get the data from */ - private static void updateColumnFromState(GridColumn column, + private static void updateColumnFromState(GridColumn column, GridColumnState state) { column.setVisible(state.visible); column.setHeaderCaption(state.header); @@ -293,23 +307,25 @@ public class GridConnector extends AbstractComponentConnector { // FIXME When something changes the header/footer rows will be // re-created. At some point we should optimize this so partial updates // can be made on the header/footer. - for (ColumnGroupRow row : getWidget().getColumnGroupRows()) { + for (ColumnGroupRow row : getWidget().getColumnGroupRows()) { getWidget().removeColumnGroupRow(row); } for (ColumnGroupRowState rowState : getState().columnGroupRows) { - ColumnGroupRow row = getWidget().addColumnGroupRow(); + ColumnGroupRow row = getWidget().addColumnGroupRow(); row.setFooterVisible(rowState.footerVisible); row.setHeaderVisible(rowState.headerVisible); for (ColumnGroupState groupState : rowState.groups) { - List> columns = new ArrayList>(); + List> columns = new ArrayList>(); for (String columnId : groupState.columns) { CustomGridColumn column = columnIdToColumn.get(columnId); columns.add(column); } - ColumnGroup group = row.addGroup(columns - .toArray(new GridColumn[columns.size()])); + @SuppressWarnings("unchecked") + final GridColumn[] gridColumns = columns + .toArray(new GridColumn[columns.size()]); + ColumnGroup group = row.addGroup(gridColumns); group.setFooterCaption(groupState.footer); group.setHeaderCaption(groupState.header); } diff --git a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java index 236fdbe9f6..b57b674292 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java @@ -102,8 +102,6 @@ public abstract class AbstractRendererConnector extends * Decodes the given JSON value into a value of type T so it can be passed * to the {@link #getRenderer() renderer}. * - * TODO This method is currently not called from anywhere - * * @param value * the value to decode * @return the decoded value of {@code value} diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index 79121af6b0..0046b256bb 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -17,7 +17,6 @@ package com.vaadin.data; import java.io.Serializable; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -26,6 +25,10 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import com.vaadin.data.Container.Indexed; import com.vaadin.data.Container.Indexed.ItemAddEvent; import com.vaadin.data.Container.Indexed.ItemRemoveEvent; @@ -41,6 +44,7 @@ import com.vaadin.server.ClientConnector; import com.vaadin.shared.data.DataProviderRpc; import com.vaadin.shared.data.DataProviderState; import com.vaadin.shared.data.DataRequestRpc; +import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.Range; import com.vaadin.ui.components.grid.Grid; import com.vaadin.ui.components.grid.GridColumn; @@ -68,8 +72,8 @@ public class RpcDataProviderExtension extends AbstractExtension { *
    *
  • listening to the currently visible {@link Property Properties'} value * changes on the server side and sending those back to the client; and - *
  • attaching and detaching {@link Component Components} from the Vaadin - * Component hierarchy. + *
  • attaching and detaching {@link com.vaadin.ui.Component Components} + * from the Vaadin Component hierarchy. *
*/ private class ActiveRowHandler implements Serializable { @@ -191,7 +195,8 @@ public class RpcDataProviderExtension extends AbstractExtension { * @param removedPropertyIds * the property ids that have been removed from the container */ - public void propertiesRemoved(Collection removedPropertyIds) { + public void propertiesRemoved(@SuppressWarnings("unused") + Collection removedPropertyIds) { /* * no-op, for now. * @@ -387,31 +392,48 @@ public class RpcDataProviderExtension extends AbstractExtension { private void pushRows(int firstRow, int numberOfRows) { List itemIds = container.getItemIds(firstRow, numberOfRows); Collection propertyIds = container.getContainerPropertyIds(); - List rows = new ArrayList(itemIds.size()); + JSONArray rows = new JSONArray(); for (Object itemId : itemIds) { - rows.add(getRowData(propertyIds, itemId)); + rows.put(getRowData(propertyIds, itemId)); } - getRpcProxy(DataProviderRpc.class).setRowData(firstRow, rows); + String jsonString = rows.toString(); + getRpcProxy(DataProviderRpc.class).setRowData(firstRow, jsonString); } - private String[] getRowData(Collection propertyIds, Object itemId) { + private JSONObject getRowData(Collection propertyIds, Object itemId) { Item item = container.getItem(itemId); - String[] row = new String[propertyIds.size()]; - int i = 0; - final Grid grid = getGrid(); - for (Object propertyId : propertyIds) { - GridColumn column = grid.getColumn(propertyId); + JSONArray rowData = new JSONArray(); + + Grid grid = getGrid(); + try { + for (Object propertyId : propertyIds) { + GridColumn column = grid.getColumn(propertyId); - Object propertyValue = item.getItemProperty(propertyId).getValue(); - Object encodedValue = encodeValue(propertyValue, - column.getRenderer(), column.getConverter(), - grid.getLocale()); + Object propertyValue = item.getItemProperty(propertyId) + .getValue(); + Object encodedValue = encodeValue(propertyValue, + column.getRenderer(), column.getConverter(), + grid.getLocale()); + + rowData.put(encodedValue); + } - // TODO Drop string conversion once client supports Objects - row[i++] = String.valueOf(encodedValue); + final JSONObject rowObject = new JSONObject(); + rowObject.put(GridState.JSONKEY_DATA, rowData); + /* + * TODO: selection wants to put here something in the lines of: + * + * rowObject.put(GridState.JSONKEY_ROWKEY, getKey(itemId)) + * + * Henrik Paul: 18.6.2014 + */ + return rowObject; + } catch (final JSONException e) { + throw new RuntimeException("Grid was unable to serialize " + + "data for row (this should've been caught " + + "eariler by other Grid logic)", e); } - return row; } @Override @@ -487,9 +509,10 @@ public class RpcDataProviderExtension extends AbstractExtension { * roundtrip. */ Object itemId = container.getIdByIndex(index); - String[] row = getRowData(container.getContainerPropertyIds(), itemId); - getRpcProxy(DataProviderRpc.class).setRowData(index, - Collections.singletonList(row)); + JSONObject row = getRowData(container.getContainerPropertyIds(), itemId); + JSONArray rowArray = new JSONArray(Collections.singleton(row)); + String jsonString = rowArray.toString(); + getRpcProxy(DataProviderRpc.class).setRowData(index, jsonString); } @Override @@ -513,10 +536,11 @@ public class RpcDataProviderExtension extends AbstractExtension { * Informs this data provider that some of the properties have been removed * from the container. *

- * Please note that we could add our own {@link PropertySetChangeListener} - * to the container, but then we'd need to implement the same bookeeping for - * finding what's added and removed that Grid already does in its own - * listener. + * Please note that we could add our own + * {@link com.vaadin.data.Container.PropertySetChangeListener + * PropertySetChangeListener} to the container, but then we'd need to + * implement the same bookeeping for finding what's added and removed that + * Grid already does in its own listener. * * @param removedColumns * a list of property ids for the removed columns @@ -529,10 +553,11 @@ public class RpcDataProviderExtension extends AbstractExtension { * Informs this data provider that some of the properties have been added to * the container. *

- * Please note that we could add our own {@link PropertySetChangeListener} - * to the container, but then we'd need to implement the same bookeeping for - * finding what's added and removed that Grid already does in its own - * listener. + * Please note that we could add our own + * {@link com.vaadin.data.Container.PropertySetChangeListener + * PropertySetChangeListener} to the container, but then we'd need to + * implement the same bookeeping for finding what's added and removed that + * Grid already does in its own listener. * * @param addedPropertyIds * a list of property ids for the added columns @@ -584,6 +609,24 @@ public class RpcDataProviderExtension extends AbstractExtension { safeConverter.getPresentationType(), locale); } - return renderer.encode(presentationValue); + Object encodedValue = renderer.encode(presentationValue); + + /* + * because this is a relatively heavy operation, we'll hide this behind + * an assert so that the check will be removed in production mode + */ + assert jsonSupports(encodedValue) : "org.json.JSONObject does not know how to serialize objects of type " + + encodedValue.getClass().getName(); + return encodedValue; + } + + private static boolean jsonSupports(Object encodedValue) { + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.accumulate("test", encodedValue); + } catch (JSONException e) { + return false; + } + return true; } } diff --git a/shared/src/com/vaadin/shared/data/DataProviderRpc.java b/shared/src/com/vaadin/shared/data/DataProviderRpc.java index a2f85159ba..a92ffe0421 100644 --- a/shared/src/com/vaadin/shared/data/DataProviderRpc.java +++ b/shared/src/com/vaadin/shared/data/DataProviderRpc.java @@ -16,8 +16,6 @@ package com.vaadin.shared.data; -import java.util.List; - import com.vaadin.shared.communication.ClientRpc; /** @@ -31,14 +29,28 @@ public interface DataProviderRpc extends ClientRpc { /** * Sends updated row data to a client. *

- * TODO rowData should be List + * rowDataJson represents a JSON array of JSON objects in the following + * format: + * + *

+     * [{
+     *   "d": [COL_1_JSON, COL_2_json, ...]
+     * },
+     * ...
+     * ]
+     * 
+ * + * where COL_INDEX is the index of the column (as a string), and COL_n_JSON + * is valid JSON of the column's data. * * @param firstRowIndex * the index of the first updated row - * @param rowData + * @param rowDataJson * the updated row data + * @see com.vaadin.shared.ui.grid.GridState#JSONKEY_DATA + * @see com.vaadin.ui.components.grid.Renderer#encode(Object) */ - public void setRowData(int firstRowIndex, List rowData); + public void setRowData(int firstRowIndex, String rowDataJson); /** * Informs the client to remove row data. diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index acb2a48e3c..eceaedd1fc 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -37,6 +37,13 @@ public class GridState extends AbstractComponentState { */ public static final double DEFAULT_HEIGHT_BY_ROWS = 10.0d; + /** + * The key in which a row's data can be found + * {@link com.vaadin.shared.data.DataProviderRpc#setRowData(int, List) + * DataProviderRpc.setRowData(int, List)} + */ + public static final String JSONKEY_DATA = "d"; + { // FIXME Grid currently does not support undefined size width = "400px"; 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..7e079e69b7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java @@ -0,0 +1,60 @@ +/* + * 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.components.grid.Grid; + +@Widgetset(TestingWidgetSet.NAME) +public class CustomRenderer extends AbstractTestUI { + + private static final Object INT_ARRAY_PROPERTY = "int array"; + + @Override + protected void setup(VaadinRequest request) { + IndexedContainer container = new IndexedContainer(); + container.addContainerProperty(INT_ARRAY_PROPERTY, int[].class, + new int[] {}); + + Object itemId = new Object(); + Item item = container.addItem(itemId); + @SuppressWarnings("unchecked") + Property property = item.getItemProperty(INT_ARRAY_PROPERTY); + property.setValue(new int[] { 1, 1, 2, 3, 5, 8, 13 }); + + Grid grid = new Grid(container); + grid.getColumn(INT_ARRAY_PROPERTY).setRenderer(new IntArrayRenderer()); + addComponent(grid); + } + + @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..1827f66777 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.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 static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Test; + +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()); + } + + private GridElement findGrid() { + List elements = $(GridElement.class).all(); + return elements.get(0); + } +} 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..9ebae4587d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.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; + +import org.json.JSONArray; +import org.json.JSONException; + +import com.vaadin.ui.components.grid.renderers.AbstractRenderer; + +public class IntArrayRenderer extends AbstractRenderer { + public IntArrayRenderer() { + super(int[].class); + } + + @Override + public Object encode(int[] value) { + try { + return new JSONArray(value); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } +} 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..be358c2738 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java @@ -0,0 +1,51 @@ +/* + * 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 { + + public class IntArrayRenderer implements Renderer { + 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 + protected IntArrayRenderer createRenderer() { + return new IntArrayRenderer(); + } + + @Override + public Class getType() { + return int[].class; + } +} -- cgit v1.2.3 From 6294a26ab8ae5df83d25318c4a8b14db34f5b8a4 Mon Sep 17 00:00:00 2001 From: Patrik Lindström Date: Tue, 17 Jun 2014 18:30:04 +0300 Subject: Implement Grid client-side Sorting API (#13334) Change-Id: I9ab18c93bdc1aaf66aa2701c3939311671a60f04 --- client/src/com/vaadin/client/ui/grid/Grid.java | 287 ++++++++++++++------- .../client/ui/grid/datasources/ListDataSource.java | 42 ++- .../src/com/vaadin/client/ui/grid/sort/Sort.java | 155 +++++++++++ .../com/vaadin/client/ui/grid/sort/SortEvent.java | 112 ++++++++ .../client/ui/grid/sort/SortEventHandler.java | 38 +++ .../com/vaadin/client/ui/grid/sort/SortOrder.java | 73 ++++++ .../vaadin/client/ui/grid/ListDataSourceTest.java | 27 +- .../com/vaadin/shared/ui/grid/SortDirection.java | 35 +++ .../tests/components/grid/GridClientRenderers.java | 24 +- .../grid/GridClientColumnRendererConnector.java | 39 ++- .../client/grid/GridClientColumnRendererRpc.java | 13 +- .../server/grid/GridClientColumnRenderers.java | 29 ++- 12 files changed, 750 insertions(+), 124 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/sort/Sort.java create mode 100644 client/src/com/vaadin/client/ui/grid/sort/SortEvent.java create mode 100644 client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/sort/SortOrder.java create mode 100644 shared/src/com/vaadin/shared/ui/grid/SortDirection.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index dfcda40b04..1739e28608 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -49,16 +49,21 @@ import com.vaadin.client.ui.grid.selection.SelectionModel; import com.vaadin.client.ui.grid.selection.SelectionModelMulti; import com.vaadin.client.ui.grid.selection.SelectionModelNone; import com.vaadin.client.ui.grid.selection.SelectionModelSingle; +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.grid.GridConstants; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.Range; import com.vaadin.shared.ui.grid.ScrollDestination; +import com.vaadin.shared.ui.grid.SortDirection; import com.vaadin.shared.util.SharedUtil; /** * A data grid view that supports columns and lazy loading of data rows from a * data source. - * + * *

Columns

*

* The {@link GridColumn} class defines the renderer used to render a cell in @@ -72,15 +77,15 @@ import com.vaadin.shared.util.SharedUtil; * specific column index using {@link Grid#getColumn(int)}. *

*

- * + * * TODO Explain about headers/footers once the multiple header/footer api has * been implemented - * + * *

Data sources

*

* TODO Explain about what a data source is and how it should be implemented. *

- * + * * @param * The row type of the grid. The row type is the POJO type from where * the data is retrieved into the column cells. @@ -213,6 +218,12 @@ public class Grid extends Composite implements */ private GridColumn lastFrozenColumn; + /** + * Current sort order. The (private) sort() method reads this list to + * determine the order in which to present rows. + */ + private List sortOrder = new ArrayList(); + private Renderer selectColumnRenderer = null; private SelectionColumn selectionColumn; @@ -269,10 +280,10 @@ public class Grid extends Composite implements /** * Base class for grid columns internally used by the Grid. The user should * use {@link GridColumn} when creating new columns. - * + * * @param * the column type - * + * * @param * the row type */ @@ -320,7 +331,7 @@ public class Grid extends Composite implements /** * Constructs a new column with a custom renderer. - * + * * @param renderer * The renderer to use for rendering the cells */ @@ -334,7 +345,7 @@ public class Grid extends Composite implements /** * Constructs a new column with custom renderers for rows, header and * footer cells. - * + * * @param bodyRenderer * The renderer to use for rendering body cells * @param headerRenderer @@ -355,7 +366,7 @@ public class Grid extends Composite implements /** * Internally used by the grid to set itself - * + * * @param grid */ private void setGrid(Grid grid) { @@ -371,7 +382,7 @@ public class Grid extends Composite implements /** * Gets text in the header of the column. By default the header caption * is empty. - * + * * @return the text displayed in the column caption */ public String getHeaderCaption() { @@ -380,7 +391,7 @@ public class Grid extends Composite implements /** * Returns the renderer used for rendering the header cells - * + * * @return a renderer that renders header cells */ public Renderer getHeaderRenderer() { @@ -389,7 +400,7 @@ public class Grid extends Composite implements /** * Sets the renderer that renders header cells. Should not be null. - * + * * @param renderer * The renderer to use for rendering header cells. */ @@ -405,7 +416,7 @@ public class Grid extends Composite implements /** * Returns the renderer used for rendering the footer cells - * + * * @return a renderer that renders footer cells */ public Renderer getFooterRenderer() { @@ -414,7 +425,7 @@ public class Grid extends Composite implements /** * Sets the renderer that renders footer cells. Should not be null. - * + * * @param renderer * The renderer to use for rendering footer cells. */ @@ -430,7 +441,7 @@ public class Grid extends Composite implements /** * Sets the text in the header of the column. - * + * * @param caption * the text displayed in the column header */ @@ -449,7 +460,7 @@ public class Grid extends Composite implements /** * Gets text in the footer of the column. By default the footer caption * is empty. - * + * * @return The text displayed in the footer of the column */ public String getFooterCaption() { @@ -458,7 +469,7 @@ public class Grid extends Composite implements /** * Sets text in the footer of the column. - * + * * @param caption * the text displayed in the footer of the column */ @@ -476,7 +487,7 @@ public class Grid extends Composite implements /** * Is the column visible. By default all columns are visible. - * + * * @return true if the column is visible */ @Override @@ -486,7 +497,7 @@ public class Grid extends Composite implements /** * Sets a column as visible in the grid. - * + * * @param visible * true if the column should be displayed in the * grid @@ -515,19 +526,26 @@ public class Grid extends Composite implements } /** - * Returns the data that should be rendered into the cell. - * + * Returns the data that should be rendered into the cell. By default + * returning Strings and Widgets are supported. If the return type is a + * String then it will be treated as preformatted text. + *

+ * To support other types you will need to pass a custom renderer to the + * column via the column constructor. + * * @param row * The row object that provides the cell content. - * + * * @return The cell content */ public abstract C getValue(T row); /** - * Returns the renderer used to render the cells of this column. - * - * @return the renderer to render the cell content with + * The renderer to render the cell width. By default renders the data as + * a String or adds the widget into the cell if the column type is of + * widget type. + * + * @return The renderer to render the cell content with */ public Renderer getRenderer() { return bodyRenderer; @@ -535,7 +553,7 @@ public class Grid extends Composite implements /** * Finds the index of this column instance - * + * */ private int findIndexOfColumn() { return grid.findVisibleColumnIndex((GridColumn) this); @@ -544,7 +562,7 @@ public class Grid extends Composite implements /** * Sets the pixel width of the column. Use a negative value for the grid * to autosize column based on content and available space - * + * * @param pixels * the width in pixels or negative for auto sizing */ @@ -561,7 +579,7 @@ public class Grid extends Composite implements /** * Returns the pixel width of the column - * + * * @return pixel width of the column */ public int getWidth() { @@ -594,7 +612,7 @@ public class Grid extends Composite implements /** * Constructs an updater for updating a header / footer - * + * * @param rows * The row container * @param inverted @@ -607,17 +625,17 @@ public class Grid extends Composite implements /** * Gets the header/footer caption value - * + * * @param column * The column to get the value for. - * + * * @return The value that should be rendered for the column caption */ public abstract String getColumnValue(GridColumn column); /** * Gets the group caption value - * + * * @param group * The group for with the caption value should be returned * @return The value that should be rendered for the column caption @@ -626,34 +644,34 @@ public class Grid extends Composite implements /** * Is the row visible in the header/footer - * + * * @param row * the row to check - * + * * @return true if the row should be visible */ public abstract boolean isRowVisible(ColumnGroupRow row); /** * Should the first row be visible - * + * * @return true if the first row should be visible */ public abstract boolean firstRowIsVisible(); /** * The renderer that renders the cell - * + * * @param column * The column for which the cell should be rendered - * + * * @return renderer used for rendering */ public abstract Renderer getRenderer(GridColumn column); /** * The renderer that renders the cell for column groups - * + * * @param group * The group that should be rendered * @return renderer used for rendering @@ -780,7 +798,7 @@ public class Grid extends Composite implements /** * Creates the header updater that updates the escalator header rows from * the column and column group rows. - * + * * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createHeaderUpdater() { @@ -950,7 +968,7 @@ public class Grid extends Composite implements /** * Creates the footer updater that updates the escalator footer rows from * the column and column group rows. - * + * * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createFooterUpdater() { @@ -990,7 +1008,7 @@ public class Grid extends Composite implements /** * Refreshes header or footer rows on demand - * + * * @param rows * The row container * @param firstRowIsVisible @@ -1042,7 +1060,7 @@ public class Grid extends Composite implements /** * Adds a column as the last column in the grid. - * + * * @param column * the column to add */ @@ -1052,7 +1070,7 @@ public class Grid extends Composite implements /** * Inserts a column into a specific position in the grid. - * + * * @param index * the index where the column should be inserted into * @param column @@ -1161,7 +1179,7 @@ public class Grid extends Composite implements /** * Removes a column from the grid. - * + * * @param column * the column to remove */ @@ -1196,7 +1214,7 @@ public class Grid extends Composite implements /** * Returns the amount of columns in the grid. - * + * * @return The number of columns in the grid */ public int getColumnCount() { @@ -1205,7 +1223,7 @@ public class Grid extends Composite implements /** * Returns a list of columns in the grid. - * + * * @return A unmodifiable list of the columns in the grid */ public List> getColumns() { @@ -1215,7 +1233,7 @@ public class Grid extends Composite implements /** * Returns a column by its index in the grid. - * + * * @param index * the index of the column * @return The column in the given index @@ -1232,30 +1250,30 @@ public class Grid extends Composite implements /** * Set the column headers visible. - * + * *

* A column header is a single cell header on top of each column reserved * for a specific header for that column. The column header can be set by * {@link GridColumn#setHeaderCaption(String)} and column headers cannot be * merged with other column headers. *

- * + * *

* All column headers occupy the first header row of the grid. If you do not * wish to show the column headers in the grid you should hide the row by * setting visibility of the header row to false. *

- * + * *

* If you want to merge the column headers into groups you can use * {@link ColumnGroupRow}s to group columns together and give them a common * header. See {@link #addColumnGroupRow()} for details. *

- * + * *

* The header row is by default visible. *

- * + * * @param visible * true if header rows should be visible */ @@ -1269,7 +1287,7 @@ public class Grid extends Composite implements /** * Are the column headers visible - * + * * @return true if they are visible */ public boolean isColumnHeadersVisible() { @@ -1278,30 +1296,30 @@ public class Grid extends Composite implements /** * Set the column footers visible. - * + * *

* A column footer is a single cell footer below of each column reserved for * a specific footer for that column. The column footer can be set by * {@link GridColumn#setFooterCaption(String)} and column footers cannot be * merged with other column footers. *

- * + * *

* All column footers occupy the first footer row of the grid. If you do not * wish to show the column footers in the grid you should hide the row by * setting visibility of the footer row to false. *

- * + * *

* If you want to merge the column footers into groups you can use * {@link ColumnGroupRow}s to group columns together and give them a common * footer. See {@link #addColumnGroupRow()} for details. *

- * + * *

* The footer row is by default hidden. *

- * + * * @param visible * true if the footer row should be visible */ @@ -1315,9 +1333,9 @@ public class Grid extends Composite implements /** * Are the column footers visible - * + * * @return true if they are visible - * + * */ public boolean isColumnFootersVisible() { return columnFootersVisible; @@ -1325,15 +1343,15 @@ public class Grid extends Composite implements /** * Adds a new column group row to the grid. - * + * *

* Column group rows are rendered in the header and footer of the grid. * Column group rows are made up of column groups which groups together * columns for adding a common auxiliary header or footer for the columns. *

- * + * * Example usage: - * + * *
      * // Add a new column group row to the grid
      * ColumnGroupRow row = grid.addColumnGroupRow();
@@ -1347,7 +1365,7 @@ public class Grid extends Composite implements
      * // Set a common footer for "Column1" and "Column2"
      * column12.setFooter("Column 1&2");
      * 
- * + * * @return a column group row instance you can use to add column groups */ public ColumnGroupRow addColumnGroupRow() { @@ -1360,10 +1378,10 @@ public class Grid extends Composite implements /** * Adds a new column group row to the grid at a specific index. - * + * * @see #addColumnGroupRow() {@link Grid#addColumnGroupRow()} for example * usage - * + * * @param rowIndex * the index where the column group row should be added * @return a column group row instance you can use to add column groups @@ -1378,7 +1396,7 @@ public class Grid extends Composite implements /** * Removes a column group row - * + * * @param row * The row to remove */ @@ -1390,9 +1408,9 @@ public class Grid extends Composite implements /** * Get the column group rows - * + * * @return a unmodifiable list of column group rows - * + * */ public List> getColumnGroupRows() { return Collections.unmodifiableList(new ArrayList>( @@ -1401,7 +1419,7 @@ public class Grid extends Composite implements /** * Returns the column group for a row and column - * + * * @param row * The row of the column * @param column @@ -1425,7 +1443,7 @@ public class Grid extends Composite implements *

* Note: This method will change the widget's size in the browser * only if {@link #getHeightMode()} returns {@link HeightMode#CSS}. - * + * * @see #setHeightMode(HeightMode) */ @Override @@ -1440,7 +1458,7 @@ public class Grid extends Composite implements /** * Sets the data source used by this grid. - * + * * @param dataSource * the data source to use, not null * @throws IllegalArgumentException @@ -1493,7 +1511,7 @@ public class Grid extends Composite implements *

* All columns up to and including the given column will be frozen in place * when the grid is scrolled sideways. - * + * * @param lastFrozenColumn * the rightmost column to freeze, or null to not * have any columns frozen @@ -1526,7 +1544,7 @@ public class Grid extends Composite implements * Note: Most usually, this method returns the very value set with * {@link #setLastFrozenColumn(GridColumn)}. This value, however, can be * reset to null if the column is removed from this grid. - * + * * @return the rightmost frozen column in the grid, or null if * no columns are frozen. */ @@ -1546,7 +1564,7 @@ public class Grid extends Composite implements /** * Scrolls to a certain row, using {@link ScrollDestination#ANY}. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @throws IllegalArgumentException @@ -1560,7 +1578,7 @@ public class Grid extends Composite implements /** * Scrolls to a certain row, using user-specified scroll destination. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @param destination @@ -1579,7 +1597,7 @@ public class Grid extends Composite implements /** * Scrolls to a certain row using only user-specified parameters. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @param destination @@ -1636,7 +1654,7 @@ public class Grid extends Composite implements *

* If Grid is currently not in {@link HeightMode#ROW}, the given value is * remembered, and applied once the mode is applied. - * + * * @param rows * The height in terms of number of rows displayed in Grid's * body. If Grid doesn't contain enough rows, white space is @@ -1648,7 +1666,7 @@ public class Grid extends Composite implements * infinite} * @throws IllegalArgumentException * if {@code rows} is {@link Double#isNaN(double) NaN} - * + * * @see #setHeightMode(HeightMode) */ public void setHeightByRows(double rows) throws IllegalArgumentException { @@ -1660,7 +1678,7 @@ public class Grid extends Composite implements * {@link #getHeightMode()} is {@link HeightMode#ROW}. *

* By default, it is {@value Escalator#DEFAULT_HEIGHT_BY_ROWS}. - * + * * @return the amount of rows that should be shown in Grid's body, while in * {@link HeightMode#ROW}. * @see #setHeightByRows(double) @@ -1680,7 +1698,7 @@ public class Grid extends Composite implements * Note: If headers/footers are inserted or removed, the widget * will resize itself to still display the required amount of rows in its * body. It also takes the horizontal scrollbar into account. - * + * * @param heightMode * the mode in to which Grid should be set */ @@ -1702,7 +1720,7 @@ public class Grid extends Composite implements * Returns the current {@link HeightMode} the Grid is in. *

* Defaults to {@link HeightMode#CSS}. - * + * * @return the current HeightMode */ public HeightMode getHeightMode() { @@ -1865,7 +1883,7 @@ public class Grid extends Composite implements /** * Accesses the package private method Widget#setParent() - * + * * @param widget * The widget to access * @param parent @@ -1878,7 +1896,7 @@ public class Grid extends Composite implements /** * Sets the current selection model. - * + * * @param selectionModel * a selection model implementation. * @throws IllegalArgumentException @@ -1896,7 +1914,7 @@ public class Grid extends Composite implements /** * Gets a reference to the current selection model. - * + * * @return the currently used SelectionModel instance. */ public SelectionModel getSelectionModel() { @@ -1907,7 +1925,7 @@ public class Grid extends Composite implements * Sets current selection mode. *

* This is a shorthand method for {@link Grid#setSelectionModel}. - * + * * @param mode * a selection mode value * @see {@link SelectionMode}. @@ -1919,7 +1937,7 @@ public class Grid extends Composite implements /** * Test if a row is selected. - * + * * @param row * a row object * @return true, if the current selection model considers the provided row @@ -1935,7 +1953,7 @@ public class Grid extends Composite implements * Only selection models implementing {@link SelectionModel.Single} and * {@link SelectionModel.Multi} are supported; for anything else, an * exception will be thrown. - * + * * @param row * a row object * @return true iff the current selection changed @@ -1960,7 +1978,7 @@ public class Grid extends Composite implements * Only selection models implementing {@link SelectionModel.Single} and * {@link SelectionModel.Multi} are supported; for anything else, an * exception will be thrown. - * + * * @param row * a row object * @return true iff the current selection changed @@ -1985,7 +2003,7 @@ public class Grid extends Composite implements * Only selection models implementing {@link SelectionModel.Single} are * valid for this method; for anything else, use the * {@link Grid#getSelectedRows()} method. - * + * * @return a selected row reference, or null, if no row is selected * @throws IllegalStateException * if the current selection model is not an instance of @@ -2002,7 +2020,7 @@ public class Grid extends Composite implements /** * Gets currently selected rows from the current selection model. - * + * * @return a non-null collection containing all currently selected rows. */ public Collection getSelectedRows() { @@ -2015,4 +2033,91 @@ public class Grid extends Composite implements return addHandler(handler, SelectionChangeEvent.getType()); } + /** + * Sets the current sort order using the fluid Sort API. Read the + * documentation for {@link Sort} for more information. + * + * @param s + * a sort instance + */ + public void sort(Sort s) { + setSortOrder(s.build()); + } + + /** + * Sorts the Grid data in ascending order along one column. + * + * @param column + * a grid column reference + */ + public void sort(GridColumn column) { + sort(column, SortDirection.ASCENDING); + } + + /** + * Sorts the Grid data along one column. + * + * @param column + * a grid column reference + * @param direction + * a sort direction value + */ + public void sort(GridColumn column, SortDirection direction) { + sort(Sort.by(column, direction)); + } + + /** + * Sets the sort order to use. Setting this causes the Grid to re-sort + * itself. + * + * @param order + * a sort order list. If set to null, the sort order is cleared. + */ + public void setSortOrder(List order) { + sortOrder.clear(); + if (order != null) { + sortOrder.addAll(order); + } + sort(); + } + + /** + * Get a copy of the current sort order array. + * + * @return a copy of the current sort order array + */ + public List getSortOrder() { + return Collections.unmodifiableList(sortOrder); + } + + /** + * Register a GWT event handler for a sorting event. This handler gets + * called whenever this Grid needs its data source to provide data sorted in + * a specific order. + * + * @param handler + * a sort event handler + * @return the registration for the event + */ + public HandlerRegistration addSortHandler(SortEventHandler handler) { + return addHandler(handler, SortEvent.getType()); + } + + /** + * Apply sorting to data source. + */ + private void sort() { + fireEvent(new SortEvent(this, + Collections.unmodifiableList(sortOrder))); + } + + /** + * Missing getDataSource method. TODO: remove this and other duplicates + * after The Merge + * + * @return a DataSource reference + */ + public DataSource getDataSource() { + return dataSource; + } } diff --git a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java index 94c32bfb33..97b358a299 100644 --- a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java +++ b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java @@ -1,12 +1,12 @@ /* * 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 @@ -18,6 +18,8 @@ package com.vaadin.client.ui.grid.datasources; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.ListIterator; @@ -30,23 +32,23 @@ import com.vaadin.shared.util.SharedUtil; * A simple list based on an in-memory data source for simply adding a list of * row pojos to the grid. Based on a wrapped list instance which supports adding * and removing of items. - * + * *

* Usage: - * + * *

  * ListDataSource<Integer> ds = new ListDataSource<Integer>(1, 2, 3, 4);
- * 
+ *
  * // Add item to the data source
  * ds.asList().add(5);
- * 
+ *
  * // Remove item from the data source
  * ds.asList().remove(3);
- * 
+ *
  * // Add multiple items
  * ds.asList().addAll(Arrays.asList(5, 6, 7));
  * 
- * + * * @since 7.4 * @author Vaadin Ltd */ @@ -342,8 +344,8 @@ public class ListDataSource implements DataSource { * data source after the data source has been constructed. To add or remove * items to the data source after it has been constructed use * {@link ListDataSource#asList()}. - * - * + * + * * @param datasource * The list to use for providing the data to the grid */ @@ -359,7 +361,7 @@ public class ListDataSource implements DataSource { * Constructs a data source with a set of rows. You can dynamically add and * remove rows from the data source via the list you get from * {@link ListDataSource#asList()} - * + * * @param rows * The rows to initially add to the data source */ @@ -401,7 +403,7 @@ public class ListDataSource implements DataSource { *

* Note: The list is not the same list as passed into the data source via * the constructor. - * + * * @return Returns a list implementation that wraps the real list that backs * the data source and provides events for the data source * listeners. @@ -416,4 +418,18 @@ public class ListDataSource implements DataSource { + row; return new RowHandleImpl(row); } + + /** + * Sort entire container according to a {@link Comparator}. + * + * @param comparator + * a comparator object, which compares two data source entries + * (beans/pojos) + */ + public void sort(Comparator comparator) { + Collections.sort(ds, comparator); + if (changeHandler != null) { + changeHandler.dataUpdated(0, ds.size()); + } + } } diff --git a/client/src/com/vaadin/client/ui/grid/sort/Sort.java b/client/src/com/vaadin/client/ui/grid/sort/Sort.java new file mode 100644 index 0000000000..fdf3c64d60 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/sort/Sort.java @@ -0,0 +1,155 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.sort; + +import java.util.ArrayList; +import java.util.List; + +import com.vaadin.client.ui.grid.GridColumn; +import com.vaadin.shared.ui.grid.SortDirection; + +/** + * Fluid Sort descriptor object. + * + * @since 7.4 + * @author Vaadin Ltd + * @param T + * grid data type + */ +public class Sort { + + private final Sort previous; + private final SortOrder order; + private final int count; + + /** + * Basic constructor, used by the {@link #by(GridColumn)} and + * {@link #by(GridColumn, SortDirection)} methods. + * + * @param column + * a grid column + * @param direction + * a sort direction + */ + private Sort(GridColumn column, SortDirection direction) { + previous = null; + count = 1; + order = new SortOrder(column, direction); + } + + /** + * Extension constructor. Performs object equality checks on all previous + * Sort objects in the chain to make sure that the column being passed in + * isn't already used earlier (which would indicate a bug). If the column + * has been used before, this constructor throws an + * {@link IllegalStateException}. + * + * @param previous + * the sort instance that the new sort instance is to extend + * @param column + * a (previously unused) grid column reference + * @param direction + * a sort direction + */ + private Sort(Sort previous, GridColumn column, SortDirection direction) { + this.previous = previous; + count = previous.count + 1; + order = new SortOrder(column, direction); + + Sort s = previous; + while (s != null) { + if (s.order.getColumn() == column) { + throw new IllegalStateException( + "Can not sort along the same column twice"); + } + s = s.previous; + } + } + + /** + * Start building a Sort order by sorting a provided column in ascending + * order. + * + * @param column + * a grid column object reference + * @return a sort instance, typed to the grid data type + */ + public static Sort by(GridColumn column) { + return by(column, SortDirection.ASCENDING); + } + + /** + * Start building a Sort order by sorting a provided column. + * + * @param column + * a grid column object reference + * @param direction + * indicator of sort direction - either ascending or descending + * @return a sort instance, typed to the grid data type + */ + public static Sort by(GridColumn column, SortDirection direction) { + return new Sort(column, direction); + } + + /** + * Continue building a Sort order. The provided column is sorted in + * ascending order if the previously added columns have been evaluated as + * equals. + * + * @param column + * a grid column object reference + * @return a sort instance, typed to the grid data type + */ + public Sort then(GridColumn column) { + return then(column, SortDirection.ASCENDING); + } + + /** + * Continue building a Sort order. The provided column is sorted in + * specified order if the previously added columns have been evaluated as + * equals. + * + * @param column + * a grid column object reference + * @param direction + * indicator of sort direction - either ascending or descending + * @return a sort instance, typed to the grid data type + */ + public Sort then(GridColumn column, SortDirection direction) { + return new Sort(this, column, direction); + } + + /** + * Build a sort order list. This method is called internally by Grid when + * calling {@link com.vaadin.client.ui.grid.Grid#sort(Sort)}, but can also + * be called manually to create a SortOrder list, which can also be provided + * directly to Grid. + * + * @return a sort order list. + */ + public List build() { + + List order = new ArrayList(count); + + Sort s = this; + for (int i = count - 1; i >= 0; --i) { + order.add(0, s.order); + s = s.previous; + } + + return order; + } +} diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java b/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java new file mode 100644 index 0000000000..d39cdfc4f2 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/sort/SortEvent.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.client.ui.grid.sort; + +import java.util.List; + +import com.google.gwt.event.shared.GwtEvent; +import com.vaadin.client.data.DataSource; +import com.vaadin.client.ui.grid.Grid; + +/** + * A sort event, fired by the Grid when it needs its data source to provide data + * sorted in a specific manner. + * + * @since 7.4 + * @author Vaadin Ltd + */ +public class SortEvent extends GwtEvent> { + + private static final Type> TYPE = new Type>(); + + private final Grid grid; + private final List order; + + /** + * Creates a new Sort Event. All provided parameters are final, and passed + * on as-is. + * + * @param grid + * a grid reference + * @param datasource + * a reference to the grid's data source + * @param order + * an array dictating the desired sort order of the data source + */ + public SortEvent(Grid grid, List order) { + this.grid = grid; + this.order = order; + } + + @Override + public Type> getAssociatedType() { + return TYPE; + } + + /** + * Static access to the GWT event type identifier associated with this Event + * class + * + * @return a type object, uniquely describing this event type. + */ + public static Type> getType() { + return TYPE; + } + + /** + * Get access to the Grid that fired this event + * + * @return the grid instance + */ + @Override + public Grid getSource() { + return grid; + } + + /** + * Get access to the Grid that fired this event + * + * @return the grid instance + */ + public Grid getGrid() { + return grid; + } + + /** + * Access the data source of the Grid that fired this event + * + * @return a data source instance + */ + public DataSource getDataSource() { + return grid.getDataSource(); + } + + /** + * Get the sort ordering that is to be applied to the Grid + * + * @return a list of sort order objects + */ + public List getOrder() { + return order; + } + + @SuppressWarnings("unchecked") + @Override + protected void dispatch(SortEventHandler handler) { + ((SortEventHandler) handler).sort(this); + } + +} diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java b/client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java new file mode 100644 index 0000000000..8895b43631 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.sort; + +import com.google.gwt.event.shared.EventHandler; + +/** + * Handler for a Grid sort event, called when the Grid needs its data source to + * provide data sorted in a specific manner. + * + * @since 7.4 + * @author Vaadin Ltd + */ +public interface SortEventHandler extends EventHandler { + + /** + * Handle sorting of the Grid. This method is called when a re-sorting of + * the Grid's data is requested. + * + * @param event + * the sort event + */ + public void sort(SortEvent event); + +} diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java new file mode 100644 index 0000000000..bd76124d0c --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.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.client.ui.grid.sort; + +import com.vaadin.client.ui.grid.GridColumn; +import com.vaadin.shared.ui.grid.SortDirection; + +/** + * Sort order descriptor. Contains column and direction references. + * + * @since 7.4 + * @author Vaadin Ltd + * @param T + * grid data type + */ +public class SortOrder { + + private final GridColumn column; + private final SortDirection direction; + + /** + * Create a sort order descriptor. + * + * @param column + * a grid column descriptor object + * @param direction + * a sorting direction value (ascending or descending) + */ + public SortOrder(GridColumn column, SortDirection direction) { + if (column == null) { + throw new IllegalArgumentException( + "Grid column reference can not be null!"); + } + if (direction == null) { + throw new IllegalArgumentException( + "Direction value can not be null!"); + } + this.column = column; + this.direction = direction; + } + + /** + * Returns the {@link GridColumn} reference given in the constructor. + * + * @return a grid column reference + */ + public GridColumn getColumn() { + return column; + } + + /** + * Returns the {@link SortDirection} value given in the constructor. + * + * @return a sort direction value + */ + public SortDirection getDirection() { + return direction; + } + +} diff --git a/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java b/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java index 5c5e88bf69..823eb224ea 100644 --- a/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java +++ b/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2013 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 @@ -16,8 +16,10 @@ package com.vaadin.client.ui.grid; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.util.Arrays; +import java.util.Comparator; import org.easymock.EasyMock; import org.junit.Test; @@ -26,7 +28,7 @@ import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.ui.grid.datasources.ListDataSource; /** - * + * * @since 7.2 * @author Vaadin Ltd */ @@ -175,4 +177,21 @@ public class ListDataSourceTest { ds.asList().iterator().remove(); } + @Test + public void sortColumn() { + ListDataSource ds = new ListDataSource(3, 4, 2, 3, 1); + + // TODO Should be simplified to sort(). No point in providing these + // trivial comparators. + ds.sort(new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return o1.compareTo(o2); + } + }); + + assertTrue(Arrays.equals(ds.asList().toArray(), new Integer[] { 1, 2, + 3, 3, 4 })); + } + } diff --git a/shared/src/com/vaadin/shared/ui/grid/SortDirection.java b/shared/src/com/vaadin/shared/ui/grid/SortDirection.java new file mode 100644 index 0000000000..3a1828992e --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/SortDirection.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.shared.ui.grid; + +/** + * Describes sorting direction for a Grid column + * + * @since 7.4 + * @author Vaadin Ltd + */ +public enum SortDirection { + + /** + * Ascending (e.g. A-Z, 1..9) sort order + */ + ASCENDING, + + /** + * Descending (e.g. Z-A, 9..1) sort order + */ + DESCENDING +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index 15bd323e08..91a4e19886 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -1,12 +1,12 @@ /* * 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 @@ -24,6 +24,7 @@ import org.openqa.selenium.WebElement; 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; @@ -33,7 +34,7 @@ import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers; /** * Tests Grid client side renderers - * + * * @since 7.4 * @author Vaadin Ltd */ @@ -161,6 +162,21 @@ public class GridClientRenderers extends MultiBrowserTest { backgroundColor); } + @Test + public void testSortingEvent() throws Exception { + openTestURL(); + + $(NativeButtonElement.class).caption("Trigger sorting").first().click(); + sleep(1000); + + String consoleText = $(LabelElement.class).id("testDebugConsole") + .getText(); + + assertTrue("Console text as expected", + consoleText.contains("Columns: 1, order: Column 1: ASCENDING")); + + } + private GridElement getGrid() { return $(MyClientGridElement.class).first(); } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index 24e79d775f..c07f6192b2 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -1,12 +1,12 @@ /* * 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 @@ -19,6 +19,8 @@ import java.util.ArrayList; 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; @@ -39,6 +41,10 @@ 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; @@ -109,7 +115,7 @@ public class GridClientColumnRendererConnector extends @Override protected void init() { Grid grid = getWidget(); - grid.setColumnHeadersVisible(false); + // grid.setColumnHeadersVisible(false); // Generated some column data List columnData = new ArrayList(); @@ -127,7 +133,25 @@ public class GridClientColumnRendererConnector extends } // Add a column to display the data in - grid.addColumn(createColumnWithRenderer(Renderers.TEXT_RENDERER)); + GridColumn c = createColumnWithRenderer(Renderers.TEXT_RENDERER); + c.setHeaderCaption("Column 1"); + grid.addColumn(c); + + // Add method for testing sort event firing + grid.addSortHandler(new SortEventHandler() { + @Override + public void sort(SortEvent event) { + Element console = Document.get().getElementById( + "testDebugConsole"); + String text = "Client-side sort event received
" + + "Columns: " + event.getOrder().size() + ", order: "; + for (SortOrder order : event.getOrder()) { + text += order.getColumn().getHeaderCaption() + ": " + + order.getDirection().toString(); + } + console.setInnerHTML(text); + } + }); // Handle RPC calls registerRpc(GridClientColumnRendererRpc.class, @@ -160,6 +184,11 @@ public class GridClientColumnRendererConnector extends // Re-attach parent.add(getWidget()); } + + @Override + public void triggerClientSorting() { + getWidget().sort(Sort.by(getWidget().getColumn(0))); + } }); } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java index d156bf9b88..ade239466e 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java @@ -1,12 +1,12 @@ /* * 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 @@ -22,7 +22,7 @@ public interface GridClientColumnRendererRpc extends ClientRpc { /** * Adds a new column with a specific renderer to the grid - * + * */ void addColumn(Renderers renderer); @@ -30,4 +30,9 @@ public interface GridClientColumnRendererRpc extends ClientRpc { * Detaches and attaches the client side Grid */ void detachAttach(); + + /** + * Used for client-side sorting API test + */ + void triggerClientSorting(); } diff --git a/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java b/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java index e968f13ff5..d41370cc02 100644 --- a/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java +++ b/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java @@ -1,12 +1,12 @@ /* * 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 @@ -19,6 +19,7 @@ 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; @@ -26,6 +27,7 @@ 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; @@ -56,6 +58,13 @@ public class GridClientColumnRenderers extends UI { public void detachAttach() { rpc().detachAttach(); } + + /** + * @since + */ + public void triggerClientSorting() { + rpc().triggerClientSorting(); + } } @Override @@ -94,5 +103,19 @@ public class GridClientColumnRenderers extends UI { } }); controls.addComponent(detachAttachBtn); + + NativeButton sortButton = new NativeButton("Trigger sorting"); + sortButton.addClickListener(new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + controller.triggerClientSorting(); + } + }); + controls.addComponent(sortButton); + + Label console = new Label(); + console.setContentMode(ContentMode.HTML); + console.setId("testDebugConsole"); + content.addComponent(console); } } -- cgit v1.2.3 From 67ad795d9e5761da1c788d4760edf290fc99391a Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Tue, 24 Jun 2014 09:52:15 +0300 Subject: Added sort indicators to Grid headers #13334 Change-Id: I35ceccea85ff0f74cbd0fd7655dba20efa25e191 --- WebContent/VAADIN/themes/base/grid/grid.scss | 14 + client/src/com/vaadin/client/ui/grid/Grid.java | 371 +++++++++++++++------ .../src/com/vaadin/client/ui/grid/sort/Sort.java | 16 +- .../com/vaadin/client/ui/grid/sort/SortOrder.java | 13 +- .../grid/GridClientColumnRendererConnector.java | 23 +- 5 files changed, 316 insertions(+), 121 deletions(-) (limited to 'uitest/src') diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index 9f7a2d8664..6a050405cb 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -1,3 +1,17 @@ @mixin base-grid($primaryStyleName : v-grid) { @include base-escalator($primaryStyleName); + + .#{$primaryStyleName} { + + th.sort-asc:after { + content: "\25B2" attr(sort-order); + float:right; + } + + th.sort-desc:after { + content: "\25BC" attr(sort-order); + float:right; + } + + } } \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 1739e28608..299aa739b3 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -26,8 +26,11 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.google.gwt.core.shared.GWT; +import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.EventTarget; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; @@ -63,7 +66,7 @@ import com.vaadin.shared.util.SharedUtil; /** * A data grid view that supports columns and lazy loading of data rows from a * data source. - * + * *

Columns

*

* The {@link GridColumn} class defines the renderer used to render a cell in @@ -77,15 +80,15 @@ import com.vaadin.shared.util.SharedUtil; * specific column index using {@link Grid#getColumn(int)}. *

*

- * + * * TODO Explain about headers/footers once the multiple header/footer api has * been implemented - * + * *

Data sources

*

* TODO Explain about what a data source is and how it should be implemented. *

- * + * * @param * The row type of the grid. The row type is the POJO type from where * the data is retrieved into the column cells. @@ -280,15 +283,165 @@ public class Grid extends Composite implements /** * Base class for grid columns internally used by the Grid. The user should * use {@link GridColumn} when creating new columns. - * + * * @param * the column type - * + * * @param * the row type */ static abstract class AbstractGridColumn implements HasVisibility { + /** + * Renderer for columns which are sortable + * + * FIXME Currently assumes multisorting + * + * FIXME Currently all columns are assumed sortable + * + */ + private class SortableColumnHeaderRenderer extends + ComplexRenderer { + + private Renderer cellRenderer; + + /** + * Creates column renderer with sort indicators + * + * @param cellRenderer + * The actual cell renderer + */ + public SortableColumnHeaderRenderer(Renderer cellRenderer) { + this.cellRenderer = cellRenderer; + } + + @Override + public void render(FlyweightCell cell, String data) { + + // Render cell + this.cellRenderer.render(cell, data); + + /* + * FIXME This grid null check is needed since Grid.addColumns() + * is invoking Escalator.insertColumn() before the grid instance + * for the column is set resulting in the first render() being + * done without a grid instance. Remove the if statement when + * this is fixed. + */ + if (grid != null) { + SortOrder sortingOrder = getSortingOrder(); + Element cellElement = cell.getElement(); + if (sortingOrder != null) { + int sortIndex = grid.getSortOrder().indexOf( + sortingOrder); + if (sortIndex > -1 && grid.getSortOrder().size() > 1) { + // Show sort order indicator if column is sorted and + // other sorted columns also exists. + cellElement.setAttribute("sort-order", + String.valueOf(sortIndex + 1)); + + } else { + cellElement.removeAttribute("sort-order"); + } + } else { + cellElement.removeAttribute("sort-order"); + cellElement.removeClassName("sort-desc"); + cellElement.removeClassName("sort-asc"); + } + } + } + + @Override + public Collection getConsumedEvents() { + return Arrays.asList(BrowserEvents.MOUSEDOWN); + } + + @Override + public void onBrowserEvent(Cell cell, NativeEvent event) { + if (BrowserEvents.MOUSEDOWN.equals(event.getType())) { + event.preventDefault(); + + SortOrder sortingOrder = getSortingOrder(); + if (sortingOrder == null) { + /* + * No previous sorting, sort Ascending + */ + sort(cell, SortDirection.ASCENDING, event.getShiftKey()); + + } else { + // Toggle sorting + SortDirection direction = sortingOrder.getDirection(); + if (direction == SortDirection.ASCENDING) { + sort(cell, SortDirection.DESCENDING, + event.getShiftKey()); + } else { + sort(cell, SortDirection.ASCENDING, + event.getShiftKey()); + } + } + } + } + + /** + * Sorts the column in a direction + */ + private void sort(Cell cell, SortDirection direction, + boolean multisort) { + TableCellElement th = TableCellElement.as(cell.getElement()); + + if (SortDirection.ASCENDING.equals(direction)) { + th.replaceClassName("sort-desc", "sort-asc"); + } else { + th.replaceClassName("sort-asc", "sort-desc"); + } + + // Apply primary sorting on clicked column + GridColumn columnInstance = getColumnInstance(); + Sort sorting = Sort.by(columnInstance, direction); + + // Re-apply old sorting to the sort order + if (multisort) { + for (SortOrder order : grid.getSortOrder()) { + if (order.getColumn() != AbstractGridColumn.this) { + sorting = sorting.then(order.getColumn(), + order.getDirection()); + } + } + } + + // Perform sorting + grid.sort(sorting); + + // Update header indicators + grid.refreshHeader(); + } + + /** + * Resolves a GridColumn out of a AbstractGridColumn + */ + private GridColumn getColumnInstance() { + for (GridColumn column : grid.getColumns()) { + if (column == AbstractGridColumn.this) { + return (GridColumn) column; + } + } + return null; + } + + /** + * Finds the sorting order for this column + */ + private SortOrder getSortingOrder() { + for (SortOrder order : grid.getSortOrder()) { + if (order.getColumn() == AbstractGridColumn.this) { + return order; + } + } + return null; + } + + } + /** * The grid the column is associated with */ @@ -322,7 +475,8 @@ public class Grid extends Composite implements /** * Renderer for rendering the header cell value into the cell */ - private Renderer headerRenderer = new TextRenderer(); + private SortableColumnHeaderRenderer headerRenderer = new SortableColumnHeaderRenderer( + new TextRenderer()); /** * Renderer for rendering the footer cell value into the cell @@ -331,7 +485,7 @@ public class Grid extends Composite implements /** * Constructs a new column with a custom renderer. - * + * * @param renderer * The renderer to use for rendering the cells */ @@ -345,7 +499,7 @@ public class Grid extends Composite implements /** * Constructs a new column with custom renderers for rows, header and * footer cells. - * + * * @param bodyRenderer * The renderer to use for rendering body cells * @param headerRenderer @@ -360,13 +514,14 @@ public class Grid extends Composite implements throw new IllegalArgumentException("Renderer cannot be null."); } - this.headerRenderer = headerRenderer; + this.headerRenderer = new SortableColumnHeaderRenderer( + headerRenderer); this.footerRenderer = footerRenderer; } /** * Internally used by the grid to set itself - * + * * @param grid */ private void setGrid(Grid grid) { @@ -382,7 +537,7 @@ public class Grid extends Composite implements /** * Gets text in the header of the column. By default the header caption * is empty. - * + * * @return the text displayed in the column caption */ public String getHeaderCaption() { @@ -391,7 +546,7 @@ public class Grid extends Composite implements /** * Returns the renderer used for rendering the header cells - * + * * @return a renderer that renders header cells */ public Renderer getHeaderRenderer() { @@ -400,7 +555,7 @@ public class Grid extends Composite implements /** * Sets the renderer that renders header cells. Should not be null. - * + * * @param renderer * The renderer to use for rendering header cells. */ @@ -408,7 +563,7 @@ public class Grid extends Composite implements if (renderer == null) { throw new IllegalArgumentException("Renderer cannot be null."); } - headerRenderer = renderer; + headerRenderer = new SortableColumnHeaderRenderer(headerRenderer); if (grid != null) { grid.refreshHeader(); } @@ -416,7 +571,7 @@ public class Grid extends Composite implements /** * Returns the renderer used for rendering the footer cells - * + * * @return a renderer that renders footer cells */ public Renderer getFooterRenderer() { @@ -425,7 +580,7 @@ public class Grid extends Composite implements /** * Sets the renderer that renders footer cells. Should not be null. - * + * * @param renderer * The renderer to use for rendering footer cells. */ @@ -441,7 +596,7 @@ public class Grid extends Composite implements /** * Sets the text in the header of the column. - * + * * @param caption * the text displayed in the column header */ @@ -460,7 +615,7 @@ public class Grid extends Composite implements /** * Gets text in the footer of the column. By default the footer caption * is empty. - * + * * @return The text displayed in the footer of the column */ public String getFooterCaption() { @@ -469,7 +624,7 @@ public class Grid extends Composite implements /** * Sets text in the footer of the column. - * + * * @param caption * the text displayed in the footer of the column */ @@ -487,7 +642,7 @@ public class Grid extends Composite implements /** * Is the column visible. By default all columns are visible. - * + * * @return true if the column is visible */ @Override @@ -497,7 +652,7 @@ public class Grid extends Composite implements /** * Sets a column as visible in the grid. - * + * * @param visible * true if the column should be displayed in the * grid @@ -532,10 +687,10 @@ public class Grid extends Composite implements *

* To support other types you will need to pass a custom renderer to the * column via the column constructor. - * + * * @param row * The row object that provides the cell content. - * + * * @return The cell content */ public abstract C getValue(T row); @@ -544,7 +699,7 @@ public class Grid extends Composite implements * The renderer to render the cell width. By default renders the data as * a String or adds the widget into the cell if the column type is of * widget type. - * + * * @return The renderer to render the cell content with */ public Renderer getRenderer() { @@ -553,7 +708,7 @@ public class Grid extends Composite implements /** * Finds the index of this column instance - * + * */ private int findIndexOfColumn() { return grid.findVisibleColumnIndex((GridColumn) this); @@ -562,7 +717,7 @@ public class Grid extends Composite implements /** * Sets the pixel width of the column. Use a negative value for the grid * to autosize column based on content and available space - * + * * @param pixels * the width in pixels or negative for auto sizing */ @@ -579,7 +734,7 @@ public class Grid extends Composite implements /** * Returns the pixel width of the column - * + * * @return pixel width of the column */ public int getWidth() { @@ -612,7 +767,7 @@ public class Grid extends Composite implements /** * Constructs an updater for updating a header / footer - * + * * @param rows * The row container * @param inverted @@ -625,17 +780,17 @@ public class Grid extends Composite implements /** * Gets the header/footer caption value - * + * * @param column * The column to get the value for. - * + * * @return The value that should be rendered for the column caption */ public abstract String getColumnValue(GridColumn column); /** * Gets the group caption value - * + * * @param group * The group for with the caption value should be returned * @return The value that should be rendered for the column caption @@ -644,34 +799,34 @@ public class Grid extends Composite implements /** * Is the row visible in the header/footer - * + * * @param row * the row to check - * + * * @return true if the row should be visible */ public abstract boolean isRowVisible(ColumnGroupRow row); /** * Should the first row be visible - * + * * @return true if the first row should be visible */ public abstract boolean firstRowIsVisible(); /** * The renderer that renders the cell - * + * * @param column * The column for which the cell should be rendered - * + * * @return renderer used for rendering */ public abstract Renderer getRenderer(GridColumn column); /** * The renderer that renders the cell for column groups - * + * * @param group * The group that should be rendered * @return renderer used for rendering @@ -798,7 +953,7 @@ public class Grid extends Composite implements /** * Creates the header updater that updates the escalator header rows from * the column and column group rows. - * + * * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createHeaderUpdater() { @@ -968,7 +1123,7 @@ public class Grid extends Composite implements /** * Creates the footer updater that updates the escalator footer rows from * the column and column group rows. - * + * * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createFooterUpdater() { @@ -1008,7 +1163,7 @@ public class Grid extends Composite implements /** * Refreshes header or footer rows on demand - * + * * @param rows * The row container * @param firstRowIsVisible @@ -1060,7 +1215,7 @@ public class Grid extends Composite implements /** * Adds a column as the last column in the grid. - * + * * @param column * the column to add */ @@ -1070,7 +1225,7 @@ public class Grid extends Composite implements /** * Inserts a column into a specific position in the grid. - * + * * @param index * the index where the column should be inserted into * @param column @@ -1179,7 +1334,7 @@ public class Grid extends Composite implements /** * Removes a column from the grid. - * + * * @param column * the column to remove */ @@ -1214,7 +1369,7 @@ public class Grid extends Composite implements /** * Returns the amount of columns in the grid. - * + * * @return The number of columns in the grid */ public int getColumnCount() { @@ -1223,7 +1378,7 @@ public class Grid extends Composite implements /** * Returns a list of columns in the grid. - * + * * @return A unmodifiable list of the columns in the grid */ public List> getColumns() { @@ -1233,7 +1388,7 @@ public class Grid extends Composite implements /** * Returns a column by its index in the grid. - * + * * @param index * the index of the column * @return The column in the given index @@ -1250,30 +1405,30 @@ public class Grid extends Composite implements /** * Set the column headers visible. - * + * *

* A column header is a single cell header on top of each column reserved * for a specific header for that column. The column header can be set by * {@link GridColumn#setHeaderCaption(String)} and column headers cannot be * merged with other column headers. *

- * + * *

* All column headers occupy the first header row of the grid. If you do not * wish to show the column headers in the grid you should hide the row by * setting visibility of the header row to false. *

- * + * *

* If you want to merge the column headers into groups you can use * {@link ColumnGroupRow}s to group columns together and give them a common * header. See {@link #addColumnGroupRow()} for details. *

- * + * *

* The header row is by default visible. *

- * + * * @param visible * true if header rows should be visible */ @@ -1287,7 +1442,7 @@ public class Grid extends Composite implements /** * Are the column headers visible - * + * * @return true if they are visible */ public boolean isColumnHeadersVisible() { @@ -1296,30 +1451,30 @@ public class Grid extends Composite implements /** * Set the column footers visible. - * + * *

* A column footer is a single cell footer below of each column reserved for * a specific footer for that column. The column footer can be set by * {@link GridColumn#setFooterCaption(String)} and column footers cannot be * merged with other column footers. *

- * + * *

* All column footers occupy the first footer row of the grid. If you do not * wish to show the column footers in the grid you should hide the row by * setting visibility of the footer row to false. *

- * + * *

* If you want to merge the column footers into groups you can use * {@link ColumnGroupRow}s to group columns together and give them a common * footer. See {@link #addColumnGroupRow()} for details. *

- * + * *

* The footer row is by default hidden. *

- * + * * @param visible * true if the footer row should be visible */ @@ -1333,9 +1488,9 @@ public class Grid extends Composite implements /** * Are the column footers visible - * + * * @return true if they are visible - * + * */ public boolean isColumnFootersVisible() { return columnFootersVisible; @@ -1343,15 +1498,15 @@ public class Grid extends Composite implements /** * Adds a new column group row to the grid. - * + * *

* Column group rows are rendered in the header and footer of the grid. * Column group rows are made up of column groups which groups together * columns for adding a common auxiliary header or footer for the columns. *

- * + * * Example usage: - * + * *
      * // Add a new column group row to the grid
      * ColumnGroupRow row = grid.addColumnGroupRow();
@@ -1365,7 +1520,7 @@ public class Grid extends Composite implements
      * // Set a common footer for "Column1" and "Column2"
      * column12.setFooter("Column 1&2");
      * 
- * + * * @return a column group row instance you can use to add column groups */ public ColumnGroupRow addColumnGroupRow() { @@ -1378,10 +1533,10 @@ public class Grid extends Composite implements /** * Adds a new column group row to the grid at a specific index. - * + * * @see #addColumnGroupRow() {@link Grid#addColumnGroupRow()} for example * usage - * + * * @param rowIndex * the index where the column group row should be added * @return a column group row instance you can use to add column groups @@ -1396,7 +1551,7 @@ public class Grid extends Composite implements /** * Removes a column group row - * + * * @param row * The row to remove */ @@ -1408,9 +1563,9 @@ public class Grid extends Composite implements /** * Get the column group rows - * + * * @return a unmodifiable list of column group rows - * + * */ public List> getColumnGroupRows() { return Collections.unmodifiableList(new ArrayList>( @@ -1419,7 +1574,7 @@ public class Grid extends Composite implements /** * Returns the column group for a row and column - * + * * @param row * The row of the column * @param column @@ -1443,7 +1598,7 @@ public class Grid extends Composite implements *

* Note: This method will change the widget's size in the browser * only if {@link #getHeightMode()} returns {@link HeightMode#CSS}. - * + * * @see #setHeightMode(HeightMode) */ @Override @@ -1458,7 +1613,7 @@ public class Grid extends Composite implements /** * Sets the data source used by this grid. - * + * * @param dataSource * the data source to use, not null * @throws IllegalArgumentException @@ -1511,7 +1666,7 @@ public class Grid extends Composite implements *

* All columns up to and including the given column will be frozen in place * when the grid is scrolled sideways. - * + * * @param lastFrozenColumn * the rightmost column to freeze, or null to not * have any columns frozen @@ -1544,7 +1699,7 @@ public class Grid extends Composite implements * Note: Most usually, this method returns the very value set with * {@link #setLastFrozenColumn(GridColumn)}. This value, however, can be * reset to null if the column is removed from this grid. - * + * * @return the rightmost frozen column in the grid, or null if * no columns are frozen. */ @@ -1564,7 +1719,7 @@ public class Grid extends Composite implements /** * Scrolls to a certain row, using {@link ScrollDestination#ANY}. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @throws IllegalArgumentException @@ -1578,7 +1733,7 @@ public class Grid extends Composite implements /** * Scrolls to a certain row, using user-specified scroll destination. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @param destination @@ -1597,7 +1752,7 @@ public class Grid extends Composite implements /** * Scrolls to a certain row using only user-specified parameters. - * + * * @param rowIndex * zero-based index of the row to scroll to. * @param destination @@ -1654,7 +1809,7 @@ public class Grid extends Composite implements *

* If Grid is currently not in {@link HeightMode#ROW}, the given value is * remembered, and applied once the mode is applied. - * + * * @param rows * The height in terms of number of rows displayed in Grid's * body. If Grid doesn't contain enough rows, white space is @@ -1666,7 +1821,7 @@ public class Grid extends Composite implements * infinite} * @throws IllegalArgumentException * if {@code rows} is {@link Double#isNaN(double) NaN} - * + * * @see #setHeightMode(HeightMode) */ public void setHeightByRows(double rows) throws IllegalArgumentException { @@ -1678,7 +1833,7 @@ public class Grid extends Composite implements * {@link #getHeightMode()} is {@link HeightMode#ROW}. *

* By default, it is {@value Escalator#DEFAULT_HEIGHT_BY_ROWS}. - * + * * @return the amount of rows that should be shown in Grid's body, while in * {@link HeightMode#ROW}. * @see #setHeightByRows(double) @@ -1698,7 +1853,7 @@ public class Grid extends Composite implements * Note: If headers/footers are inserted or removed, the widget * will resize itself to still display the required amount of rows in its * body. It also takes the horizontal scrollbar into account. - * + * * @param heightMode * the mode in to which Grid should be set */ @@ -1720,7 +1875,7 @@ public class Grid extends Composite implements * Returns the current {@link HeightMode} the Grid is in. *

* Defaults to {@link HeightMode#CSS}. - * + * * @return the current HeightMode */ public HeightMode getHeightMode() { @@ -1748,10 +1903,22 @@ public class Grid extends Composite implements RowContainer container = escalator.findRowContainer(e); if (container != null) { Cell cell = container.getCell(e); - Renderer renderer = columns.get(cell.getColumn()) - .getRenderer(); - if (renderer instanceof ComplexRenderer) { - ((ComplexRenderer) renderer).onBrowserEvent(cell, event); + if (cell != null) { + GridColumn gridColumn = columns.get(cell.getColumn()); + + Renderer renderer; + if (container == escalator.getHeader()) { + renderer = gridColumn.getHeaderRenderer(); + } else if (container == escalator.getFooter()) { + renderer = gridColumn.getFooterRenderer(); + } else { + renderer = gridColumn.getRenderer(); + } + + if (renderer instanceof ComplexRenderer) { + ((ComplexRenderer) renderer).onBrowserEvent(cell, + event); + } } } } @@ -1883,7 +2050,7 @@ public class Grid extends Composite implements /** * Accesses the package private method Widget#setParent() - * + * * @param widget * The widget to access * @param parent @@ -1896,7 +2063,7 @@ public class Grid extends Composite implements /** * Sets the current selection model. - * + * * @param selectionModel * a selection model implementation. * @throws IllegalArgumentException @@ -1914,7 +2081,7 @@ public class Grid extends Composite implements /** * Gets a reference to the current selection model. - * + * * @return the currently used SelectionModel instance. */ public SelectionModel getSelectionModel() { @@ -1925,7 +2092,7 @@ public class Grid extends Composite implements * Sets current selection mode. *

* This is a shorthand method for {@link Grid#setSelectionModel}. - * + * * @param mode * a selection mode value * @see {@link SelectionMode}. @@ -1937,7 +2104,7 @@ public class Grid extends Composite implements /** * Test if a row is selected. - * + * * @param row * a row object * @return true, if the current selection model considers the provided row @@ -1953,7 +2120,7 @@ public class Grid extends Composite implements * Only selection models implementing {@link SelectionModel.Single} and * {@link SelectionModel.Multi} are supported; for anything else, an * exception will be thrown. - * + * * @param row * a row object * @return true iff the current selection changed @@ -1978,7 +2145,7 @@ public class Grid extends Composite implements * Only selection models implementing {@link SelectionModel.Single} and * {@link SelectionModel.Multi} are supported; for anything else, an * exception will be thrown. - * + * * @param row * a row object * @return true iff the current selection changed @@ -2003,7 +2170,7 @@ public class Grid extends Composite implements * Only selection models implementing {@link SelectionModel.Single} are * valid for this method; for anything else, use the * {@link Grid#getSelectedRows()} method. - * + * * @return a selected row reference, or null, if no row is selected * @throws IllegalStateException * if the current selection model is not an instance of @@ -2020,7 +2187,7 @@ public class Grid extends Composite implements /** * Gets currently selected rows from the current selection model. - * + * * @return a non-null collection containing all currently selected rows. */ public Collection getSelectedRows() { @@ -2036,7 +2203,7 @@ public class Grid extends Composite implements /** * Sets the current sort order using the fluid Sort API. Read the * documentation for {@link Sort} for more information. - * + * * @param s * a sort instance */ @@ -2046,7 +2213,7 @@ public class Grid extends Composite implements /** * Sorts the Grid data in ascending order along one column. - * + * * @param column * a grid column reference */ @@ -2056,7 +2223,7 @@ public class Grid extends Composite implements /** * Sorts the Grid data along one column. - * + * * @param column * a grid column reference * @param direction @@ -2069,7 +2236,7 @@ public class Grid extends Composite implements /** * Sets the sort order to use. Setting this causes the Grid to re-sort * itself. - * + * * @param order * a sort order list. If set to null, the sort order is cleared. */ @@ -2083,7 +2250,7 @@ public class Grid extends Composite implements /** * Get a copy of the current sort order array. - * + * * @return a copy of the current sort order array */ public List getSortOrder() { @@ -2094,7 +2261,7 @@ public class Grid extends Composite implements * Register a GWT event handler for a sorting event. This handler gets * called whenever this Grid needs its data source to provide data sorted in * a specific order. - * + * * @param handler * a sort event handler * @return the registration for the event @@ -2114,7 +2281,7 @@ public class Grid extends Composite implements /** * Missing getDataSource method. TODO: remove this and other duplicates * after The Merge - * + * * @return a DataSource reference */ public DataSource getDataSource() { diff --git a/client/src/com/vaadin/client/ui/grid/sort/Sort.java b/client/src/com/vaadin/client/ui/grid/sort/Sort.java index fdf3c64d60..64fec445ae 100644 --- a/client/src/com/vaadin/client/ui/grid/sort/Sort.java +++ b/client/src/com/vaadin/client/ui/grid/sort/Sort.java @@ -23,7 +23,7 @@ import com.vaadin.shared.ui.grid.SortDirection; /** * Fluid Sort descriptor object. - * + * * @since 7.4 * @author Vaadin Ltd * @param T @@ -38,7 +38,7 @@ public class Sort { /** * Basic constructor, used by the {@link #by(GridColumn)} and * {@link #by(GridColumn, SortDirection)} methods. - * + * * @param column * a grid column * @param direction @@ -56,7 +56,7 @@ public class Sort { * isn't already used earlier (which would indicate a bug). If the column * has been used before, this constructor throws an * {@link IllegalStateException}. - * + * * @param previous * the sort instance that the new sort instance is to extend * @param column @@ -82,7 +82,7 @@ public class Sort { /** * Start building a Sort order by sorting a provided column in ascending * order. - * + * * @param column * a grid column object reference * @return a sort instance, typed to the grid data type @@ -93,7 +93,7 @@ public class Sort { /** * Start building a Sort order by sorting a provided column. - * + * * @param column * a grid column object reference * @param direction @@ -108,7 +108,7 @@ public class Sort { * Continue building a Sort order. The provided column is sorted in * ascending order if the previously added columns have been evaluated as * equals. - * + * * @param column * a grid column object reference * @return a sort instance, typed to the grid data type @@ -121,7 +121,7 @@ public class Sort { * Continue building a Sort order. The provided column is sorted in * specified order if the previously added columns have been evaluated as * equals. - * + * * @param column * a grid column object reference * @param direction @@ -137,7 +137,7 @@ public class Sort { * calling {@link com.vaadin.client.ui.grid.Grid#sort(Sort)}, but can also * be called manually to create a SortOrder list, which can also be provided * directly to Grid. - * + * * @return a sort order list. */ public List build() { diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java index bd76124d0c..09b1a48afa 100644 --- a/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java +++ b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java @@ -20,7 +20,7 @@ import com.vaadin.shared.ui.grid.SortDirection; /** * Sort order descriptor. Contains column and direction references. - * + * * @since 7.4 * @author Vaadin Ltd * @param T @@ -33,7 +33,7 @@ public class SortOrder { /** * Create a sort order descriptor. - * + * * @param column * a grid column descriptor object * @param direction @@ -54,7 +54,7 @@ public class SortOrder { /** * Returns the {@link GridColumn} reference given in the constructor. - * + * * @return a grid column reference */ public GridColumn getColumn() { @@ -63,11 +63,16 @@ public class SortOrder { /** * Returns the {@link SortDirection} value given in the constructor. - * + * * @return a sort direction value */ public SortDirection getDirection() { return direction; } + @Override + public String toString() { + return column.getHeaderCaption() + " (" + direction + ")"; + } + } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index c07f6192b2..95052917c1 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -115,7 +115,6 @@ public class GridClientColumnRendererConnector extends @Override protected void init() { Grid grid = getWidget(); - // grid.setColumnHeadersVisible(false); // Generated some column data List columnData = new ArrayList(); @@ -161,15 +160,25 @@ public class GridClientColumnRendererConnector extends public void addColumn(Renderers renderer) { if (renderer == Renderers.NUMBER_RENDERER) { - getWidget().addColumn( - createNumberColumnWithRenderer(renderer)); + GridColumn numberColumn = createNumberColumnWithRenderer(renderer); + numberColumn.setHeaderCaption("Column " + + String.valueOf(getWidget() + .getColumnCount() + 1)); + getWidget().addColumn(numberColumn); + } else if (renderer == Renderers.DATE_RENDERER) { - getWidget().addColumn( - createDateColumnWithRenderer(renderer)); + GridColumn dateColumn = createDateColumnWithRenderer(renderer); + dateColumn.setHeaderCaption("Column " + + String.valueOf(getWidget() + .getColumnCount() + 1)); + getWidget().addColumn(dateColumn); } else { - getWidget().addColumn( - createColumnWithRenderer(renderer)); + GridColumn column = createColumnWithRenderer(renderer); + column.setHeaderCaption("Column " + + String.valueOf(getWidget() + .getColumnCount() + 1)); + getWidget().addColumn(column); } } -- cgit v1.2.3 From 8f71585df37d3f0e2e55ceac9e6abbaf2806855e Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Wed, 25 Jun 2014 11:16:46 +0300 Subject: Allow turning sorting on/off for columns #13334 Change-Id: I161dfd2cd534cdf4fc13467811f77be7d8cbc339 --- client/src/com/vaadin/client/ui/grid/Grid.java | 105 ++++++++++++++------- .../com/vaadin/client/ui/grid/GridConnector.java | 1 + server/src/com/vaadin/ui/components/grid/Grid.java | 8 ++ .../com/vaadin/ui/components/grid/GridColumn.java | 18 ++++ .../com/vaadin/shared/ui/grid/GridColumnState.java | 5 + .../tests/components/grid/GridBasicFeatures.java | 15 +++ 6 files changed, 119 insertions(+), 33 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 299aa739b3..a1c4b4308a 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -296,9 +296,6 @@ public class Grid extends Composite implements * Renderer for columns which are sortable * * FIXME Currently assumes multisorting - * - * FIXME Currently all columns are assumed sortable - * */ private class SortableColumnHeaderRenderer extends ComplexRenderer { @@ -331,26 +328,36 @@ public class Grid extends Composite implements if (grid != null) { SortOrder sortingOrder = getSortingOrder(); Element cellElement = cell.getElement(); - if (sortingOrder != null) { - int sortIndex = grid.getSortOrder().indexOf( - sortingOrder); - if (sortIndex > -1 && grid.getSortOrder().size() > 1) { - // Show sort order indicator if column is sorted and - // other sorted columns also exists. - cellElement.setAttribute("sort-order", - String.valueOf(sortIndex + 1)); - + if (grid.getColumn(cell.getColumn()).isSortable()) { + if (sortingOrder != null) { + int sortIndex = grid.getSortOrder().indexOf( + sortingOrder); + if (sortIndex > -1 + && grid.getSortOrder().size() > 1) { + // Show sort order indicator if column is sorted + // and other sorted columns also exists. + cellElement.setAttribute("sort-order", + String.valueOf(sortIndex + 1)); + + } else { + cellElement.removeAttribute("sort-order"); + } } else { - cellElement.removeAttribute("sort-order"); + cleanup(cell); } } else { - cellElement.removeAttribute("sort-order"); - cellElement.removeClassName("sort-desc"); - cellElement.removeClassName("sort-asc"); + cleanup(cell); } } } + private void cleanup(FlyweightCell cell) { + Element cellElement = cell.getElement(); + cellElement.removeAttribute("sort-order"); + cellElement.removeClassName("sort-desc"); + cellElement.removeClassName("sort-asc"); + } + @Override public Collection getConsumedEvents() { return Arrays.asList(BrowserEvents.MOUSEDOWN); @@ -358,25 +365,31 @@ public class Grid extends Composite implements @Override public void onBrowserEvent(Cell cell, NativeEvent event) { - if (BrowserEvents.MOUSEDOWN.equals(event.getType())) { - event.preventDefault(); - SortOrder sortingOrder = getSortingOrder(); - if (sortingOrder == null) { - /* - * No previous sorting, sort Ascending - */ - sort(cell, SortDirection.ASCENDING, event.getShiftKey()); + // Handle sorting events if column is sortable + if (grid.getColumn(cell.getColumn()).isSortable()) { + if (BrowserEvents.MOUSEDOWN.equals(event.getType())) { + event.preventDefault(); - } else { - // Toggle sorting - SortDirection direction = sortingOrder.getDirection(); - if (direction == SortDirection.ASCENDING) { - sort(cell, SortDirection.DESCENDING, - event.getShiftKey()); - } else { + SortOrder sortingOrder = getSortingOrder(); + if (sortingOrder == null) { + /* + * No previous sorting, sort Ascending + */ sort(cell, SortDirection.ASCENDING, event.getShiftKey()); + + } else { + // Toggle sorting + SortDirection direction = sortingOrder + .getDirection(); + if (direction == SortDirection.ASCENDING) { + sort(cell, SortDirection.DESCENDING, + event.getShiftKey()); + } else { + sort(cell, SortDirection.ASCENDING, + event.getShiftKey()); + } } } } @@ -439,7 +452,6 @@ public class Grid extends Composite implements } return null; } - } /** @@ -475,7 +487,7 @@ public class Grid extends Composite implements /** * Renderer for rendering the header cell value into the cell */ - private SortableColumnHeaderRenderer headerRenderer = new SortableColumnHeaderRenderer( + private Renderer headerRenderer = new SortableColumnHeaderRenderer( new TextRenderer()); /** @@ -483,6 +495,8 @@ public class Grid extends Composite implements */ private Renderer footerRenderer = new TextRenderer(); + private boolean sortable = false; + /** * Constructs a new column with a custom renderer. * @@ -747,6 +761,31 @@ public class Grid extends Composite implements return conf.getColumnWidth(index); } } + + /** + * Enables sort indicators for the grid. + *

+ * Note:The API can still sort the column even if this is set to + * false. + * + * @param sortable + * true when column sort indicators are visible. + */ + public void setSortable(boolean sortable) { + if (this.sortable != sortable) { + this.sortable = sortable; + grid.refreshHeader(); + } + } + + /** + * Are sort indicators shown for the column. + * + * @return true if the column is sortable + */ + public boolean isSortable() { + return sortable; + } } /** diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 95b493b451..0bfcf8ffcd 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -272,6 +272,7 @@ public class GridConnector extends AbstractComponentConnector { column.setHeaderCaption(state.header); column.setFooterCaption(state.footer); column.setWidth(state.width); + column.setSortable(state.sortable); } /** diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 0d7e799978..1ebf227330 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -30,6 +30,7 @@ import com.vaadin.data.Container; import com.vaadin.data.Container.PropertySetChangeEvent; import com.vaadin.data.Container.PropertySetChangeListener; import com.vaadin.data.Container.PropertySetChangeNotifier; +import com.vaadin.data.Container.Sortable; import com.vaadin.data.RpcDataProviderExtension; import com.vaadin.server.KeyMapper; import com.vaadin.shared.ui.grid.ColumnGroupRowState; @@ -253,6 +254,13 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { if (!columns.containsKey(propertyId)) { GridColumn column = appendColumn(propertyId); + // Initial sorting is defined by container + if (datasource instanceof Sortable) { + column.setSortable(((Sortable) datasource) + .getSortableContainerPropertyIds().contains( + propertyId)); + } + // Add by default property id as column header column.setHeaderCaption(String.valueOf(propertyId)); } diff --git a/server/src/com/vaadin/ui/components/grid/GridColumn.java b/server/src/com/vaadin/ui/components/grid/GridColumn.java index fd504fdae3..634526ea7c 100644 --- a/server/src/com/vaadin/ui/components/grid/GridColumn.java +++ b/server/src/com/vaadin/ui/components/grid/GridColumn.java @@ -395,4 +395,22 @@ public class GridColumn implements Serializable { grid.getPropertyIdByColumnId(state.id)); } + /** + * Should sorting controls be available for the column + * + * @param sortable + * true if the sorting controls should be visible. + */ + public void setSortable(boolean sortable) { + checkColumnIsAttached(); + state.sortable = sortable; + grid.markAsDirty(); + } + + /** + * Are the sorting controls visible in the column header + */ + public boolean isSortable() { + return state.sortable; + } } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java b/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java index 581d4d4365..d1df08c294 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java @@ -55,4 +55,9 @@ public class GridColumnState implements Serializable { public int width = 100; public Connector rendererConnector; + + /** + * Are sorting indicators shown for a column. Default is false. + */ + public boolean sortable = false; } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index 1dc500202e..06fe088dee 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -192,6 +192,21 @@ public class GridBasicFeatures extends AbstractComponentTest { } }, null, c); + createBooleanAction("Sortable", getColumnProperty(c), true, + new Command() { + + @Override + public void execute(Grid grid, Boolean value, + Object columnIndex) { + Object propertyId = (new ArrayList(grid + .getContainerDatasource() + .getContainerPropertyIds()) + .get((Integer) columnIndex)); + GridColumn column = grid.getColumn(propertyId); + column.setSortable(value); + } + }, c); + createCategory("Column" + c + " Width", getColumnProperty(c)); createClickAction("Auto", "Column" + c + " Width", -- cgit v1.2.3 From c4a1ee8a4fbc3fafaabea695d8aaf40aecbeba48 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Tue, 10 Jun 2014 21:50:51 +0300 Subject: Send selection between server and client (#13334) Change-Id: I75174af63092fca72d9aa63ccf3c06a77f42c4f6 --- WebContent/VAADIN/themes/base/grid/grid.scss | 6 +- .../client/data/AbstractRemoteDataSource.java | 2 +- .../vaadin/client/data/RpcDataSourceConnector.java | 26 +- .../src/com/vaadin/client/ui/grid/Escalator.java | 3 + client/src/com/vaadin/client/ui/grid/Grid.java | 44 +++- .../com/vaadin/client/ui/grid/GridConnector.java | 91 ++++++- .../ui/grid/selection/MultiSelectionRenderer.java | 26 +- .../client/ui/grid/selection/SelectionModel.java | 34 +-- .../ui/grid/selection/SelectionModelMulti.java | 50 +++- .../ui/grid/selection/SelectionModelNone.java | 4 +- .../ui/grid/selection/SelectionModelSingle.java | 39 +-- .../com/vaadin/data/RpcDataProviderExtension.java | 278 ++++++++++++++++++--- server/src/com/vaadin/ui/components/grid/Grid.java | 127 +++++++++- .../grid/selection/SelectionChangeEvent.java | 10 +- .../component/grid/DataProviderExtension.java | 88 +++++++ .../com/vaadin/shared/data/DataProviderRpc.java | 3 +- .../com/vaadin/shared/ui/grid/GridServerRpc.java | 30 +++ .../src/com/vaadin/shared/ui/grid/GridState.java | 14 +- .../tests/components/grid/GridBasicFeatures.java | 14 ++ .../components/grid/GridBasicFeaturesTest.java | 78 ++++++ .../tests/components/grid/GridClientRenderers.java | 9 + 21 files changed, 850 insertions(+), 126 deletions(-) create mode 100644 server/tests/src/com/vaadin/tests/server/component/grid/DataProviderExtension.java create mode 100644 shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java (limited to 'uitest/src') diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index 6a050405cb..d1875a7ab3 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -14,4 +14,8 @@ } } -} \ No newline at end of file + + .#{$primaryStyleName}-row-selected > td { + background: lightblue; + } +} diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java index 2395dc848c..d6a609a3c8 100644 --- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java +++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java @@ -42,7 +42,7 @@ import com.vaadin.shared.ui.grid.Range; */ public abstract class AbstractRemoteDataSource implements DataSource { - private class RowHandleImpl extends RowHandle { + protected class RowHandleImpl extends RowHandle { private T row; private final Object key; diff --git a/client/src/com/vaadin/client/data/RpcDataSourceConnector.java b/client/src/com/vaadin/client/data/RpcDataSourceConnector.java index 2b9bf5c90e..3761ea92df 100644 --- a/client/src/com/vaadin/client/data/RpcDataSourceConnector.java +++ b/client/src/com/vaadin/client/data/RpcDataSourceConnector.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; +import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; import com.vaadin.client.ServerConnector; import com.vaadin.client.extensions.AbstractExtensionConnector; @@ -29,6 +30,7 @@ import com.vaadin.shared.data.DataProviderRpc; import com.vaadin.shared.data.DataProviderState; import com.vaadin.shared.data.DataRequestRpc; import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.Range; /** @@ -43,7 +45,8 @@ import com.vaadin.shared.ui.grid.Range; @Connect(com.vaadin.data.RpcDataProviderExtension.class) public class RpcDataSourceConnector extends AbstractExtensionConnector { - private final AbstractRemoteDataSource dataSource = new AbstractRemoteDataSource() { + public class RpcDataSource extends AbstractRemoteDataSource { + @Override protected void requestRows(int firstRowIndex, int numberOfRows) { Range cached = getCachedRange(); @@ -54,18 +57,25 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { @Override public Object getRowKey(JSONObject row) { - /* - * FIXME will be properly implemented by another patch (Henrik Paul: - * 16.6.2014) - */ - return row; + JSONString string = row.get(GridState.JSONKEY_ROWKEY).isString(); + if (string != null) { + return string.stringValue(); + } else { + return null; + } + } + + public RowHandle getHandleByKey(Object key) { + return new RowHandleImpl(null, key); } - }; + } + + private final RpcDataSource dataSource = new RpcDataSource(); @Override protected void extend(ServerConnector target) { dataSource.setEstimatedSize(getState().containerSize); - ((GridConnector) target).getWidget().setDataSource(dataSource); + ((GridConnector) target).setDataSource(dataSource); registerRpc(DataProviderRpc.class, new DataProviderRpc() { @Override diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index 8a1f6f5842..c8feb6d18e 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -2678,6 +2678,9 @@ public class Escalator extends Widget { @Override protected void paintRemoveRows(final int index, final int numberOfRows) { + if (numberOfRows == 0) { + return; + } final Range viewportRange = Range.withLength( getLogicalRowIndex(visualRowOrder.getFirst()), diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index b5461e4a3b..9a75b37c42 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -48,7 +48,6 @@ import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.TextRenderer; import com.vaadin.client.ui.grid.renderers.WidgetRenderer; import com.vaadin.client.ui.grid.selection.HasSelectionChangeHandlers; -import com.vaadin.client.ui.grid.selection.MultiSelectionRenderer; import com.vaadin.client.ui.grid.selection.SelectionChangeEvent; import com.vaadin.client.ui.grid.selection.SelectionChangeHandler; import com.vaadin.client.ui.grid.selection.SelectionModel; @@ -1061,7 +1060,7 @@ public class Grid extends Composite implements refreshHeader(); refreshFooter(); - selectionModel = SelectionMode.SINGLE.createModel(); + setSelectionMode(SelectionMode.SINGLE); escalator .addRowVisibilityChangeHandler(new RowVisibilityChangeHandler() { @@ -1075,6 +1074,16 @@ public class Grid extends Composite implements } } }); + + // Default action on SelectionChangeEvents. Refresh the body so changed + // become visible. + addSelectionChangeHandler(new SelectionChangeHandler() { + + @Override + public void onSelectionChange(SelectionChangeEvent event) { + refreshBody(); + } + }); } @Override @@ -1340,6 +1349,13 @@ public class Grid extends Composite implements true); } + /** + * Refreshes all body rows + */ + private void refreshBody() { + escalator.getBody().refreshRows(0, escalator.getBody().getRowCount()); + } + /** * Refreshes all footer rows */ @@ -1796,6 +1812,15 @@ public class Grid extends Composite implements } + /** + * Gets the {@Link DataSource} for this Grid. + * + * @return the data source used by this grid + */ + public DataSource getDataSource() { + return dataSource; + } + /** * Sets the rightmost frozen column in the grid. *

@@ -2177,7 +2202,7 @@ public class Grid extends Composite implements /* TODO remove before final */ public void setSelectionCheckboxes(boolean set) { if (set) { - setSelectColumnRenderer(new MultiSelectionRenderer(this)); + setSelectColumnRenderer(selectionModel.getSelectionColumnRenderer()); } else { setSelectColumnRenderer(null); } @@ -2198,6 +2223,8 @@ public class Grid extends Composite implements /** * Sets the current selection model. + *

+ * This function will call {@link SelectionModel#setGrid(Grid)}. * * @param selectionModel * a selection model implementation. @@ -2211,6 +2238,7 @@ public class Grid extends Composite implements } this.selectionModel = selectionModel; + selectionModel.setGrid(this); } @@ -2412,14 +2440,4 @@ public class Grid extends Composite implements fireEvent(new SortEvent(this, Collections.unmodifiableList(sortOrder))); } - - /** - * Missing getDataSource method. TODO: remove this and other duplicates - * after The Merge - * - * @return a DataSource reference - */ - public DataSource getDataSource() { - return dataSource; - } } diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 0bfcf8ffcd..3b1ecb44d8 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -17,9 +17,11 @@ package com.vaadin.client.ui.grid; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -28,13 +30,18 @@ import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONValue; import com.vaadin.client.communication.StateChangeEvent; +import com.vaadin.client.data.RpcDataSourceConnector.RpcDataSource; import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; +import com.vaadin.client.ui.grid.selection.SelectionChangeEvent; +import com.vaadin.client.ui.grid.selection.SelectionChangeHandler; +import com.vaadin.client.ui.grid.selection.SelectionModelMulti; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.grid.ColumnGroupRowState; import com.vaadin.shared.ui.grid.ColumnGroupState; import com.vaadin.shared.ui.grid.GridClientRpc; import com.vaadin.shared.ui.grid.GridColumnState; +import com.vaadin.shared.ui.grid.GridServerRpc; import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.ScrollDestination; @@ -53,7 +60,66 @@ import com.vaadin.shared.ui.grid.ScrollDestination; public class GridConnector extends AbstractComponentConnector { /** - * Custom implementation of the custom grid column using a String[] to + * Hacked SelectionModelMulti to make selection communication work for now. + */ + private class RowKeyBasedMultiSelection extends + SelectionModelMulti { + + private final LinkedHashSet selectedKeys = new LinkedHashSet(); + + public List getSelectedKeys() { + List keys = new ArrayList(); + keys.addAll(selectedKeys); + return keys; + } + + public void updateFromState() { + boolean changed = false; + Set stateKeys = new LinkedHashSet(); + stateKeys.addAll(getState().selectedKeys); + for (String key : stateKeys) { + if (!selectedKeys.contains(key)) { + changed = true; + selectByHandle(dataSource.getHandleByKey(key)); + } + } + for (String key : selectedKeys) { + changed = true; + if (!stateKeys.contains(key)) { + deselectByHandle(dataSource.getHandleByKey(key)); + } + } + selectedKeys.clear(); + selectedKeys.addAll(stateKeys); + + if (changed) { + // At least for now there's no way to send the selected and/or + // deselected row data. Some data is only stored as keys + getWidget().fireEvent( + new SelectionChangeEvent(getWidget(), + (List) null, null)); + } + } + + @Override + public boolean select(Collection rows) { + for (JSONObject row : rows) { + selectedKeys.add((String) dataSource.getRowKey(row)); + } + return super.select(rows); + } + + @Override + public boolean deselect(Collection rows) { + for (JSONObject row : rows) { + selectedKeys.remove(dataSource.getRowKey(row)); + } + return super.deselect(rows); + } + } + + /** + * Custom implementation of the custom grid column using a JSONObject to * represent the cell value and String as a column type. */ private class CustomGridColumn extends GridColumn { @@ -107,6 +173,8 @@ public class GridConnector extends AbstractComponentConnector { * Maps a generated column id to a grid column instance */ private Map columnIdToColumn = new HashMap(); + private final RowKeyBasedMultiSelection selectionModel = new RowKeyBasedMultiSelection(); + private RpcDataSource dataSource; @Override @SuppressWarnings("unchecked") @@ -139,6 +207,18 @@ public class GridConnector extends AbstractComponentConnector { getWidget().scrollToRow(row, destination); } }); + + getWidget().setSelectionModel(selectionModel); + + getWidget().addSelectionChangeHandler(new SelectionChangeHandler() { + @Override + public void onSelectionChange(SelectionChangeEvent event) { + // TODO change this to diff based. (henrik paul 24.6.2014) + getRpcProxy(GridServerRpc.class).selectionChange( + selectionModel.getSelectedKeys()); + } + }); + } @Override @@ -211,6 +291,10 @@ public class GridConnector extends AbstractComponentConnector { if (stateChangeEvent.hasPropertyChanged("heightMode")) { getWidget().setHeightMode(getState().heightMode); } + + if (stateChangeEvent.hasPropertyChanged("selectedKeys")) { + selectionModel.updateFromState(); + } } /** @@ -332,4 +416,9 @@ public class GridConnector extends AbstractComponentConnector { } } } + + public void setDataSource(RpcDataSource dataSource) { + this.dataSource = dataSource; + getWidget().setDataSource(this.dataSource); + } } diff --git a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java index 52bb6c0f60..53b0d064ab 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java @@ -17,7 +17,6 @@ package com.vaadin.client.ui.grid.selection; import java.util.Collection; import java.util.HashSet; -import java.util.logging.Logger; import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.Element; @@ -37,7 +36,7 @@ import com.vaadin.client.ui.grid.Grid; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; /* This class will probably not survive the final merge of all selection functionality. */ -public class MultiSelectionRenderer extends ComplexRenderer { +public class MultiSelectionRenderer extends ComplexRenderer { private class TouchEventHandler implements NativePreviewHandler { @Override @@ -168,12 +167,12 @@ public class MultiSelectionRenderer extends ComplexRenderer { private static final String LOGICAL_ROW_PROPERTY_INT = "vEscalatorLogicalRow"; - private final Grid grid; + private final Grid grid; private HandlerRegistration nativePreviewHandlerRegistration; private final SelectionHandler selectionHandler = new SelectionHandler(); - public MultiSelectionRenderer(final Grid grid) { + public MultiSelectionRenderer(final Grid grid) { this.grid = grid; } @@ -276,23 +275,16 @@ public class MultiSelectionRenderer extends ComplexRenderer { } } - private boolean isSelected(final int logicalRow) { - // TODO - // return grid.getSelectionModel().isSelected(logicalRow); - return false; + protected boolean isSelected(final int logicalRow) { + return grid.isSelected(grid.getDataSource().getRow(logicalRow)); } - private void setSelected(final int logicalRow, final boolean select) { + protected void setSelected(final int logicalRow, final boolean select) { + T row = grid.getDataSource().getRow(logicalRow); if (select) { - // TODO - // grid.getSelectionModel().select(logicalRow); - Logger.getLogger(getClass().getName()).warning( - "Selecting " + logicalRow); + grid.select(row); } else { - // TODO - // grid.getSelectionModel().deselect(logicalRow); - Logger.getLogger(getClass().getName()).warning( - "Deselecting " + logicalRow); + grid.deselect(row); } } } diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModel.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModel.java index d11b7764d0..989a8946c7 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModel.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModel.java @@ -25,7 +25,7 @@ import com.vaadin.client.ui.grid.Renderer; *

* Selection models perform tracking of selected rows in the Grid, as well as * dispatching events when the selection state changes. - * + * * @author Vaadin Ltd * @since 7.4 * @param @@ -36,7 +36,7 @@ public interface SelectionModel { /** * Return true if the provided row is considered selected under the * implementing selection model. - * + * * @param row * row object instance * @return true, if the row given as argument is considered @@ -47,18 +47,18 @@ public interface SelectionModel { /** * Return the {@link Renderer} responsible for rendering the selection * column. - * + * * @return a renderer instance. If null is returned, a selection column will * not be drawn. */ - public Renderer getSelectionColumnRenderer(); + public Renderer getSelectionColumnRenderer(); /** * Tells this SelectionModel which Grid it belongs to. *

* Implementations are free to have this be a no-op. This method is called * internally by Grid. - * + * * @param grid * a {@link Grid} instance */ @@ -74,7 +74,7 @@ public interface SelectionModel { /** * Returns a Collection containing all selected rows. - * + * * @return a non-null collection. */ public Collection getSelectedRows(); @@ -82,7 +82,7 @@ public interface SelectionModel { /** * Selection model that allows a maximum of one row to be selected at any * one time. - * + * * @param * type parameter corresponding with Grid row type */ @@ -90,7 +90,7 @@ public interface SelectionModel { /** * Selects a row. - * + * * @param row * a {@link Grid} row object * @return true, if this row as not previously selected. @@ -101,7 +101,7 @@ public interface SelectionModel { * Deselects a row. *

* This is a no-op unless {@link row} is the currently selected row. - * + * * @param row * a {@link Grid} row object * @return true, if the currently selected row was deselected. @@ -110,7 +110,7 @@ public interface SelectionModel { /** * Returns the currently selected row. - * + * * @return a {@link Grid} row object or null, if nothing is selected. */ public T getSelectedRow(); @@ -119,7 +119,7 @@ public interface SelectionModel { /** * Selection model that allows for several rows to be selected at once. - * + * * @param * type parameter corresponding with Grid row type */ @@ -127,7 +127,7 @@ public interface SelectionModel { /** * Selects one or more rows. - * + * * @param rows * {@link Grid} row objects * @return true, if the set of selected rows was changed. @@ -136,7 +136,7 @@ public interface SelectionModel { /** * Deselects one or more rows. - * + * * @param rows * Grid row objects * @return true, if the set of selected rows was changed. @@ -145,14 +145,14 @@ public interface SelectionModel { /** * De-selects all rows. - * + * * @return true, if any row was previously selected. */ public boolean deselectAll(); /** * Select all rows in a {@link Collection}. - * + * * @param rows * a collection of Grid row objects * @return true, if the set of selected rows was changed. @@ -161,7 +161,7 @@ public interface SelectionModel { /** * Deselect all rows in a {@link Collection}. - * + * * @param rows * a collection of Grid row objects * @return true, if the set of selected rows was changed. @@ -173,7 +173,7 @@ public interface SelectionModel { /** * Interface for a selection model that does not allow anything to be * selected. - * + * * @param * type parameter corresponding with Grid row type */ diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java index 8afb592771..de62dc9cbc 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java @@ -17,38 +17,38 @@ package com.vaadin.client.ui.grid.selection; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import com.vaadin.client.data.DataSource.RowHandle; import com.vaadin.client.ui.grid.Grid; import com.vaadin.client.ui.grid.Renderer; /** * Multi-row selection model. - * + * * @author Vaadin Ltd * @since 7.4 */ public class SelectionModelMulti implements SelectionModel.Multi { - private final Renderer renderer; - private final Set selectedRows; + private final Set> selectedRows; + private Renderer renderer; private Grid grid; public SelectionModelMulti() { grid = null; renderer = null; - selectedRows = new LinkedHashSet(); + selectedRows = new LinkedHashSet>(); } @Override public boolean isSelected(T row) { - return selectedRows.contains(row); + return isSelectedByHandle(grid.getDataSource().getHandle(row)); } @Override - public Renderer getSelectionColumnRenderer() { + public Renderer getSelectionColumnRenderer() { return renderer; } @@ -64,6 +64,8 @@ public class SelectionModelMulti implements SelectionModel.Multi { throw new IllegalStateException( "Grid reference cannot be reassigned"); } + + this.renderer = new MultiSelectionRenderer(grid); } @Override @@ -87,7 +89,7 @@ public class SelectionModelMulti implements SelectionModel.Multi { if (selectedRows.size() > 0) { SelectionChangeEvent event = new SelectionChangeEvent(grid, - null, selectedRows); + null, getSelectedRows()); selectedRows.clear(); grid.fireEvent(event); @@ -105,7 +107,8 @@ public class SelectionModelMulti implements SelectionModel.Multi { Set added = new LinkedHashSet(); for (T row : rows) { - if (selectedRows.add(row)) { + RowHandle handle = grid.getDataSource().getHandle(row); + if (selectByHandle(handle)) { added.add(row); } } @@ -127,7 +130,7 @@ public class SelectionModelMulti implements SelectionModel.Multi { Set removed = new LinkedHashSet(); for (T row : rows) { - if (selectedRows.remove(row)) { + if (deselectByHandle(grid.getDataSource().getHandle(row))) { removed.add(row); } } @@ -140,14 +143,37 @@ public class SelectionModelMulti implements SelectionModel.Multi { return false; } + protected boolean isSelectedByHandle(RowHandle handle) { + return selectedRows.contains(handle); + } + + protected boolean selectByHandle(RowHandle handle) { + if (selectedRows.add(handle)) { + handle.pin(); + return true; + } + return false; + } + + protected boolean deselectByHandle(RowHandle handle) { + if (selectedRows.remove(handle)) { + handle.unpin(); + return true; + } + return false; + } + @Override public Collection getSelectedRows() { - return Collections.unmodifiableSet(selectedRows); + Set selected = new LinkedHashSet(); + for (RowHandle handle : selectedRows) { + selected.add(handle.getRow()); + } + return selected; } @Override public void reset() { deselectAll(); } - } diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java index bcb0357089..93dfb49df2 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java @@ -23,7 +23,7 @@ import com.vaadin.client.ui.grid.Renderer; /** * No-row selection model. - * + * * @author Vaadin Ltd * @since 7.4 */ @@ -35,7 +35,7 @@ public class SelectionModelNone implements SelectionModel.None { } @Override - public Renderer getSelectionColumnRenderer() { + public Renderer getSelectionColumnRenderer() { return null; } diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java index 6b5f645e23..775e1878c5 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java @@ -18,30 +18,31 @@ package com.vaadin.client.ui.grid.selection; import java.util.Collection; import java.util.Collections; +import com.vaadin.client.data.DataSource.RowHandle; import com.vaadin.client.ui.grid.Grid; import com.vaadin.client.ui.grid.Renderer; /** * Single-row selection model. - * + * * @author Vaadin Ltd * @since 7.4 */ public class SelectionModelSingle implements SelectionModel.Single { private Grid grid; - private T selectedRow; + private RowHandle selectedRow; + private Renderer renderer; @Override public boolean isSelected(T row) { - return row == null ? null : row.equals(getSelectedRow()); + return selectedRow != null + && selectedRow.equals(grid.getDataSource().getHandle(row)); } @Override - public Renderer getSelectionColumnRenderer() { - // TODO: Add implementation of SelectionColumnRenderer; currently none - // exists - return null; + public Renderer getSelectionColumnRenderer() { + return renderer; } @Override @@ -56,6 +57,7 @@ public class SelectionModelSingle implements SelectionModel.Single { throw new IllegalStateException( "Grid reference cannot be reassigned"); } + renderer = new MultiSelectionRenderer(grid); } @Override @@ -65,12 +67,17 @@ public class SelectionModelSingle implements SelectionModel.Single { throw new IllegalArgumentException("Row cannot be null"); } - if (row.equals(getSelectedRow())) { + if (isSelected(row)) { return false; } - T removed = selectedRow; - selectedRow = row; + T removed = getSelectedRow(); + if (selectedRow != null) { + selectedRow.unpin(); + } + selectedRow = grid.getDataSource().getHandle(row); + selectedRow.pin(); + grid.fireEvent(new SelectionChangeEvent(grid, row, removed)); return true; @@ -83,8 +90,9 @@ public class SelectionModelSingle implements SelectionModel.Single { throw new IllegalArgumentException("Row cannot be null"); } - if (row.equals(selectedRow)) { - T removed = selectedRow; + if (isSelected(row)) { + T removed = selectedRow.getRow(); + selectedRow.unpin(); selectedRow = null; grid.fireEvent(new SelectionChangeEvent(grid, null, removed)); return true; @@ -95,16 +103,15 @@ public class SelectionModelSingle implements SelectionModel.Single { @Override public T getSelectedRow() { - return selectedRow; + return (selectedRow != null ? selectedRow.getRow() : null); } @Override public void reset() { - T removed = selectedRow; - selectedRow = null; + T removed = getSelectedRow(); if (removed != null) { - grid.fireEvent(new SelectionChangeEvent(grid, null, removed)); + deselect(removed); } } diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index 0046b256bb..1834822d99 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -17,6 +17,7 @@ package com.vaadin.data; import java.io.Serializable; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -24,11 +25,14 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import com.google.gwt.thirdparty.guava.common.collect.BiMap; +import com.google.gwt.thirdparty.guava.common.collect.HashBiMap; import com.vaadin.data.Container.Indexed; import com.vaadin.data.Container.Indexed.ItemAddEvent; import com.vaadin.data.Container.Indexed.ItemRemoveEvent; @@ -62,6 +66,227 @@ import com.vaadin.ui.components.grid.Renderer; */ public class RpcDataProviderExtension extends AbstractExtension { + /** + * ItemId to Key to ItemId mapper. + *

+ * This class is used when transmitting information about items in container + * related to Grid. It introduces a consistent way of mapping ItemIds and + * its container to a String that can be mapped back to ItemId. + *

+ * Technical note: This class also keeps tabs on which indices are + * being shown/selected, and is able to clean up after itself once the + * itemId ⇆ key mapping is not needed anymore. In other words, this + * doesn't leak memory. + */ + public class DataProviderKeyMapper { + private final BiMap indexToItemId = HashBiMap.create(); + private final BiMap itemIdToKey = HashBiMap.create(); + private Set pinnedItemIds = new HashSet(); + private Range activeRange = Range.withLength(0, 0); + private long rollingIndex = 0; + + private DataProviderKeyMapper() { + // private implementation + } + + void preActiveRowsChange(Range newActiveRange, int firstNewIndex, + List itemIds) { + final Range[] removed = activeRange.partitionWith(newActiveRange); + final Range[] added = newActiveRange.partitionWith(activeRange); + + removeActiveRows(removed[0]); + removeActiveRows(removed[2]); + addActiveRows(added[0], firstNewIndex, itemIds); + addActiveRows(added[2], firstNewIndex, itemIds); + + activeRange = newActiveRange; + } + + private void removeActiveRows(final Range deprecated) { + for (int i = deprecated.getStart(); i < deprecated.getEnd(); i++) { + final Integer ii = Integer.valueOf(i); + final Object itemId = indexToItemId.get(ii); + + if (!pinnedItemIds.contains(itemId)) { + itemIdToKey.remove(itemId); + } + indexToItemId.remove(ii); + } + } + + private void addActiveRows(final Range added, int firstNewIndex, + List newItemIds) { + + for (int i = added.getStart(); i < added.getEnd(); i++) { + + /* + * We might be in a situation we have an index <-> itemId entry + * already. This happens when something was selected, scrolled + * out of view and now we're scrolling it back into view. It's + * unnecessary to overwrite it in that case. + * + * Fun thought: considering branch prediction, it _might_ even + * be a bit faster to simply always run the code beyond this + * if-state. But it sounds too stupid (and most often too + * insignificant) to try out. + */ + final Integer ii = Integer.valueOf(i); + if (indexToItemId.containsKey(ii)) { + continue; + } + + /* + * We might be in a situation where we have an itemId <-> key + * entry already, but no index for it. This happens when + * something that is out of view is selected programmatically. + * In that case, we only want to add an index for that entry, + * and not overwrite the key. + */ + final Object itemId = newItemIds.get(i - firstNewIndex); + if (!itemIdToKey.containsKey(itemId)) { + itemIdToKey.put(itemId, nextKey()); + } + indexToItemId.put(ii, itemId); + } + } + + private String nextKey() { + return String.valueOf(rollingIndex++); + } + + String getKey(Object itemId) { + String key = itemIdToKey.get(itemId); + if (key == null) { + key = nextKey(); + itemIdToKey.put(itemId, key); + } + return key; + } + + /** + * Gets keys for a collection of item ids. + *

+ * If the itemIds are currently cached, the existing keys will be used. + * Otherwise new ones will be created. + * + * @param itemIds + * the item ids for which to get keys + * @return keys for the {@code itemIds} + */ + public List getKeys(Collection itemIds) { + if (itemIds == null) { + throw new IllegalArgumentException("itemIds can't be null"); + } + + ArrayList keys = new ArrayList(itemIds.size()); + for (Object itemId : itemIds) { + keys.add(getKey(itemId)); + } + return keys; + } + + Object getItemId(String key) throws IllegalStateException { + Object itemId = itemIdToKey.inverse().get(key); + if (itemId != null) { + return itemId; + } else { + throw new IllegalStateException("No item id for key " + key + + " found."); + } + } + + /** + * Gets corresponding item ids for each of the keys in a collection. + * + * @param keys + * the keys for which to retrieve item ids + * @return a collection of item ids for the {@code keys} + * @throws IllegalStateException + * if one or more of keys don't have a corresponding item id + * in the cache + */ + public Collection getItemIds(Collection keys) + throws IllegalStateException { + if (keys == null) { + throw new IllegalArgumentException("keys may not be null"); + } + + ArrayList itemIds = new ArrayList(keys.size()); + for (String key : keys) { + itemIds.add(getItemId(key)); + } + return itemIds; + } + + /** + * Pin an item id to be cached indefinitely. + *

+ * Normally when an itemId is not an active row, it is discarded from + * the cache. Pinning an item id will make sure that it is kept in the + * cache. + *

+ * In effect, while an item id is pinned, it always has the same key. + * + * @param itemId + * the item id to pin + * @throws IllegalStateException + * if {@code itemId} was already pinned + * @see #unpin(Object) + * @see #isPinned(Object) + * @see #getItemIds(Collection) + */ + public void pin(Object itemId) throws IllegalStateException { + if (isPinned(itemId)) { + throw new IllegalStateException("Item id " + itemId + + " was pinned already"); + } + pinnedItemIds.add(itemId); + } + + /** + * Unpin an item id. + *

+ * This cancels the effect of pinning an item id. If the item id is + * currently inactive, it will be immediately removed from the cache. + * + * @param itemId + * the item id to unpin + * @throws IllegalStateException + * if {@code itemId} was not pinned + * @see #pin(Object) + * @see #isPinned(Object) + * @see #getItemIds(Collection) + */ + public void unpin(Object itemId) throws IllegalStateException { + if (!isPinned(itemId)) { + throw new IllegalStateException("Item id " + itemId + + " was not pinned"); + } + + pinnedItemIds.remove(itemId); + final Integer removedIndex = indexToItemId.inverse().remove(itemId); + if (removedIndex == null + || !activeRange.contains(removedIndex.intValue())) { + itemIdToKey.remove(itemId); + } + } + + /** + * Checks whether an item id is pinned or not. + * + * @param itemId + * the item id to check for pin status + * @return {@code true} iff the item id is currently pinned + */ + public boolean isPinned(Object itemId) { + return pinnedItemIds.contains(itemId); + } + + Object itemIdAtIndex(int index) { + return indexToItemId.inverse().get(Integer.valueOf(index)); + } + } + /** * A helper class that handles the client-side Escalator logic relating to * making sure that whatever is currently visible to the user, is properly @@ -70,8 +295,9 @@ public class RpcDataProviderExtension extends AbstractExtension { *

* This bookeeping includes, but is not limited to: *

    - *
  • listening to the currently visible {@link Property Properties'} value - * changes on the server side and sending those back to the client; and + *
  • listening to the currently visible {@link com.vaadin.data.Property + * Properties'} value changes on the server side and sending those back to + * the client; and *
  • attaching and detaching {@link com.vaadin.ui.Component Components} * from the Vaadin Component hierarchy. *
@@ -340,7 +566,7 @@ public class RpcDataProviderExtension extends AbstractExtension { ItemRemoveEvent removeEvent = (ItemRemoveEvent) event; int firstIndex = removeEvent.getFirstIndex(); int count = removeEvent.getRemovedItemsCount(); - removeRowData(firstIndex, count, removeEvent.getFirstItemId()); + removeRowData(firstIndex, count); } else { @@ -353,6 +579,8 @@ public class RpcDataProviderExtension extends AbstractExtension { } }; + private final DataProviderKeyMapper keyMapper = new DataProviderKeyMapper(); + /** * Creates a new data provider using the given container. * @@ -366,8 +594,6 @@ public class RpcDataProviderExtension extends AbstractExtension { @Override public void requestRows(int firstRow, int numberOfRows, int firstCachedRowIndex, int cacheSize) { - pushRows(firstRow, numberOfRows); - Range active = Range.withLength(firstRow, numberOfRows); if (cacheSize != 0) { Range cached = Range.withLength(firstCachedRowIndex, @@ -375,6 +601,11 @@ public class RpcDataProviderExtension extends AbstractExtension { active = active.combineWith(cached); } + List itemIds = RpcDataProviderExtension.this.container + .getItemIds(firstRow, numberOfRows); + keyMapper.preActiveRowsChange(active, firstRow, itemIds); + pushRows(firstRow, itemIds); + activeRowHandler.setActiveRows(active.getStart(), active.length()); } @@ -389,8 +620,7 @@ public class RpcDataProviderExtension extends AbstractExtension { } - private void pushRows(int firstRow, int numberOfRows) { - List itemIds = container.getItemIds(firstRow, numberOfRows); + private void pushRows(int firstRow, List itemIds) { Collection propertyIds = container.getContainerPropertyIds(); JSONArray rows = new JSONArray(); for (Object itemId : itemIds) { @@ -402,6 +632,7 @@ public class RpcDataProviderExtension extends AbstractExtension { private JSONObject getRowData(Collection propertyIds, Object itemId) { Item item = container.getItem(itemId); + String[] row = new String[propertyIds.size()]; JSONArray rowData = new JSONArray(); @@ -421,13 +652,7 @@ public class RpcDataProviderExtension extends AbstractExtension { final JSONObject rowObject = new JSONObject(); rowObject.put(GridState.JSONKEY_DATA, rowData); - /* - * TODO: selection wants to put here something in the lines of: - * - * rowObject.put(GridState.JSONKEY_ROWKEY, getKey(itemId)) - * - * Henrik Paul: 18.6.2014 - */ + rowObject.put(GridState.JSONKEY_ROWKEY, keyMapper.getKey(itemId)); return rowObject; } catch (final JSONException e) { throw new RuntimeException("Grid was unable to serialize " @@ -477,23 +702,16 @@ public class RpcDataProviderExtension extends AbstractExtension { * @param firstItemId * the item id of the first removed item */ - private void removeRowData(int firstIndex, int count, Object firstItemId) { + private void removeRowData(int firstIndex, int count) { getState().containerSize -= count; getRpcProxy(DataProviderRpc.class).removeRowData(firstIndex, count); - /* - * Unfortunately, there's no sane way of getting the rest of the removed - * itemIds unless we cache a mapping between index and itemId. - * - * Fortunately, the only time _currently_ an event with more than one - * removed item seems to be when calling - * AbstractInMemoryContainer.removeAllElements(). Otherwise, it's only - * removing one item at a time. - * - * We _could_ have a backup of all the itemIds, and compare to that one, - * but we really really don't want to go there. - */ - activeRowHandler.removeItemId(firstItemId); + for (int i = 0; i < count; i++) { + Object itemId = keyMapper.itemIdAtIndex(firstIndex + i); + if (itemId != null) { + activeRowHandler.removeItemId(itemId); + } + } } /** @@ -566,6 +784,10 @@ public class RpcDataProviderExtension extends AbstractExtension { activeRowHandler.propertiesAdded(addedPropertyIds); } + public DataProviderKeyMapper getKeyMapper() { + return keyMapper; + } + protected Grid getGrid() { return (Grid) getParent(); } diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 1ebf227330..bc6a69e850 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -26,16 +26,23 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import org.json.JSONArray; +import org.json.JSONException; + +import com.google.gwt.thirdparty.guava.common.collect.Sets; +import com.google.gwt.thirdparty.guava.common.collect.Sets.SetView; import com.vaadin.data.Container; import com.vaadin.data.Container.PropertySetChangeEvent; import com.vaadin.data.Container.PropertySetChangeListener; import com.vaadin.data.Container.PropertySetChangeNotifier; import com.vaadin.data.Container.Sortable; import com.vaadin.data.RpcDataProviderExtension; +import com.vaadin.data.RpcDataProviderExtension.DataProviderKeyMapper; import com.vaadin.server.KeyMapper; import com.vaadin.shared.ui.grid.ColumnGroupRowState; import com.vaadin.shared.ui.grid.GridClientRpc; import com.vaadin.shared.ui.grid.GridColumnState; +import com.vaadin.shared.ui.grid.GridServerRpc; import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.ScrollDestination; @@ -181,6 +188,15 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { */ private SelectionModel selectionModel; + /** + * The number of times to ignore selection state sync to the client. + *

+ * This usually means that the client side has modified the selection. We + * still want to inform the listeners that the selection has changed, but we + * don't want to send those changes "back to the client". + */ + private int ignoreSelectionClientSync = 0; + private static final Method SELECTION_CHANGE_METHOD = ReflectTools .findMethod(SelectionChangeListener.class, "selectionChange", SelectionChangeEvent.class); @@ -191,9 +207,105 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * @param datasource * the data source for the grid */ - public Grid(Container.Indexed datasource) { + public Grid(final Container.Indexed datasource) { setContainerDataSource(datasource); setSelectionMode(SelectionMode.MULTI); + addSelectionChangeListener(new SelectionChangeListener() { + @Override + public void selectionChange(SelectionChangeEvent event) { + for (Object removedItemId : event.getRemoved()) { + keyMapper().unpin(removedItemId); + } + + for (Object addedItemId : event.getAdded()) { + keyMapper().pin(addedItemId); + } + + List keys = keyMapper().getKeys(getSelectedRows()); + + boolean markAsDirty = true; + + /* + * If this clause is true, it means that the selection event + * originated from the client. This means that we don't want to + * send the changes back to the client (markAsDirty => false). + */ + if (ignoreSelectionClientSync > 0) { + ignoreSelectionClientSync--; + markAsDirty = false; + + try { + + /* + * Make sure that the diffstate is aware of the + * "undirty" modification, so that the diffs are + * calculated correctly the next time we actually want + * to send the selection state to the client. + */ + getUI().getConnectorTracker().getDiffState(Grid.this) + .put("selectedKeys", new JSONArray(keys)); + } catch (JSONException e) { + throw new RuntimeException("Internal error", e); + } + } + + getState(markAsDirty).selectedKeys = keys; + } + }); + + registerRpc(new GridServerRpc() { + + @Override + public void selectionChange(List selection) { + final HashSet newSelection = new HashSet( + keyMapper().getItemIds(selection)); + final HashSet oldSelection = new HashSet( + getSelectedRows()); + + SetView addedItemIds = Sets.difference(newSelection, + oldSelection); + SetView removedItemIds = Sets.difference(oldSelection, + newSelection); + + if (!addedItemIds.isEmpty()) { + /* + * Since these changes come from the client, we want to + * modify the selection model and get that event fired to + * all the listeners. One of the listeners is our internal + * selection listener, and this tells it not to send the + * selection event back to the client. + */ + ignoreSelectionClientSync++; + + if (addedItemIds.size() == 1) { + select(addedItemIds.iterator().next()); + } else { + assert getSelectionModel() instanceof SelectionModel.Multi : "Got multiple selections, but the selection model is not a SelectionModel.Multi"; + ((SelectionModel.Multi) getSelectionModel()) + .select(addedItemIds); + } + } + + if (!removedItemIds.isEmpty()) { + /* + * Since these changes come from the client, we want to + * modify the selection model and get that event fired to + * all the listeners. One of the listeners is our internal + * selection listener, and this tells it not to send the + * selection event back to the client. + */ + ignoreSelectionClientSync++; + + if (removedItemIds.size() == 1) { + deselect(removedItemIds.iterator().next()); + } else { + assert getSelectionModel() instanceof SelectionModel.Multi : "Got multiple deselections, but the selection model is not a SelectionModel.Multi"; + ((SelectionModel.Multi) getSelectionModel()) + .deselect(removedItemIds); + } + } + } + }); } /** @@ -205,6 +317,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * if the data source is null */ public void setContainerDataSource(Container.Indexed container) { + if (container == null) { throw new IllegalArgumentException( "Cannot set the datasource to null"); @@ -935,11 +1048,21 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { SELECTION_CHANGE_METHOD); } - /** FIXME remove once selection mode communcation is done. only for testing. */ + /** + * FIXME remove once selection mode communication is done. only for testing. + */ public void setSelectionCheckboxes(boolean value) { getState().selectionCheckboxes = value; } + /** + * A shortcut for + * {@link #datasourceExtension}.{@link com.vaadin.data.RpcDataProviderExtension#getKeyMapper() getKeyMapper()} + */ + private DataProviderKeyMapper keyMapper() { + return datasourceExtension.getKeyMapper(); + } + /** * Adds a renderer to this grid's connector hierarchy. * diff --git a/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeEvent.java b/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeEvent.java index cecdca80df..f0e25405cc 100644 --- a/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeEvent.java +++ b/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeEvent.java @@ -17,7 +17,7 @@ package com.vaadin.ui.components.grid.selection; import java.util.Collection; import java.util.EventObject; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import com.google.gwt.thirdparty.guava.common.collect.Sets; @@ -32,14 +32,14 @@ import com.vaadin.ui.components.grid.Grid; */ public class SelectionChangeEvent extends EventObject { - private Set oldSelection; - private Set newSelection; + private LinkedHashSet oldSelection; + private LinkedHashSet newSelection; public SelectionChangeEvent(Grid source, Collection oldSelection, Collection newSelection) { super(source); - this.oldSelection = new HashSet(oldSelection); - this.newSelection = new HashSet(newSelection); + this.oldSelection = new LinkedHashSet(oldSelection); + this.newSelection = new LinkedHashSet(newSelection); } /** diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/DataProviderExtension.java b/server/tests/src/com/vaadin/tests/server/component/grid/DataProviderExtension.java new file mode 100644 index 0000000000..9ecf131c5b --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/grid/DataProviderExtension.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.server.component.grid; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.data.Container; +import com.vaadin.data.Container.Indexed; +import com.vaadin.data.Item; +import com.vaadin.data.Property; +import com.vaadin.data.RpcDataProviderExtension; +import com.vaadin.data.RpcDataProviderExtension.DataProviderKeyMapper; +import com.vaadin.data.util.IndexedContainer; + +public class DataProviderExtension { + private RpcDataProviderExtension dataProvider; + private DataProviderKeyMapper keyMapper; + private Container.Indexed container; + + private static final Object ITEM_ID1 = "itemid1"; + private static final Object ITEM_ID2 = "itemid2"; + private static final Object ITEM_ID3 = "itemid3"; + + private static final Object PROPERTY_ID1_STRING = "property1"; + + @Before + public void setup() { + container = new IndexedContainer(); + populate(container); + + dataProvider = new RpcDataProviderExtension(container); + keyMapper = dataProvider.getKeyMapper(); + } + + private static void populate(Indexed container) { + container.addContainerProperty(PROPERTY_ID1_STRING, String.class, ""); + for (Object itemId : Arrays.asList(ITEM_ID1, ITEM_ID2, ITEM_ID3)) { + final Item item = container.addItem(itemId); + @SuppressWarnings("unchecked") + final Property stringProperty = item + .getItemProperty(PROPERTY_ID1_STRING); + stringProperty.setValue(itemId.toString()); + } + } + + @Test + public void pinBasics() { + assertFalse("itemId1 should not start as pinned", + keyMapper.isPinned(ITEM_ID2)); + + keyMapper.pin(ITEM_ID1); + assertTrue("itemId1 should now be pinned", keyMapper.isPinned(ITEM_ID1)); + + keyMapper.unpin(ITEM_ID1); + assertFalse("itemId1 should not be pinned anymore", + keyMapper.isPinned(ITEM_ID2)); + } + + @Test(expected = IllegalStateException.class) + public void doublePinning() { + keyMapper.pin(ITEM_ID1); + keyMapper.pin(ITEM_ID1); + } + + @Test(expected = IllegalStateException.class) + public void nonexistentUnpin() { + keyMapper.unpin(ITEM_ID1); + } +} diff --git a/shared/src/com/vaadin/shared/data/DataProviderRpc.java b/shared/src/com/vaadin/shared/data/DataProviderRpc.java index a92ffe0421..43469914e5 100644 --- a/shared/src/com/vaadin/shared/data/DataProviderRpc.java +++ b/shared/src/com/vaadin/shared/data/DataProviderRpc.java @@ -34,7 +34,8 @@ public interface DataProviderRpc extends ClientRpc { * *
      * [{
-     *   "d": [COL_1_JSON, COL_2_json, ...]
+     *   "d": [COL_1_JSON, COL_2_json, ...],
+     *   "k": "1"
      * },
      * ...
      * ]
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java
new file mode 100644
index 0000000000..b763174e53
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.grid;
+
+import java.util.List;
+
+import com.vaadin.shared.communication.ServerRpc;
+
+/**
+ * Client-to-server RPC interface for the Grid component
+ * 
+ * @since 7.4
+ * @author Vaadin Ltd
+ */
+public interface GridServerRpc extends ServerRpc {
+    void selectionChange(List newSelection);
+}
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java
index eceaedd1fc..0b23e2c11d 100644
--- a/shared/src/com/vaadin/shared/ui/grid/GridState.java
+++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java
@@ -39,11 +39,18 @@ public class GridState extends AbstractComponentState {
 
     /**
      * The key in which a row's data can be found
-     * {@link com.vaadin.shared.data.DataProviderRpc#setRowData(int, List)
-     * DataProviderRpc.setRowData(int, List)}
+     * 
+     * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String)
      */
     public static final String JSONKEY_DATA = "d";
 
+    /**
+     * The key in which a row's own key can be found
+     * 
+     * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String)
+     */
+    public static final String JSONKEY_ROWKEY = "k";
+
     {
         // FIXME Grid currently does not support undefined size
         width = "400px";
@@ -97,4 +104,7 @@ public class GridState extends AbstractComponentState {
     @DelegateToWidget
     public boolean selectionCheckboxes;
 
+    // instantiated just to avoid NPEs
+    public List selectedKeys = new ArrayList();
+
 }
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java
index 06fe088dee..c6597ef23b 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java
@@ -363,6 +363,20 @@ public class GridBasicFeatures extends AbstractComponentTest {
                         }
                     }
                 }, null);
+
+        createBooleanAction("Select first row", "Body rows", false,
+                new Command() {
+                    @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);
+                        }
+                    }
+                });
     }
 
     @SuppressWarnings("boxing")
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java
index a11b0f1be9..3dc8ac814f 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java
@@ -18,6 +18,7 @@ package com.vaadin.tests.components.grid;
 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.ArrayList;
@@ -301,6 +302,83 @@ public class GridBasicFeaturesTest extends MultiBrowserTest {
                 "modified: Column0", getBodyCellByRowAndColumn(0, 0).getText());
     }
 
+    @Test
+    public void testSelectOnOff() throws Exception {
+        openTestURL();
+
+        assertFalse("row shouldn't start out as selected",
+                isSelected(getRow(0)));
+        toggleFirstRowSelection();
+        assertTrue("row should become selected", isSelected(getRow(0)));
+        toggleFirstRowSelection();
+        assertFalse("row shouldn't remain selected", isSelected(getRow(0)));
+    }
+
+    @Test
+    public void testSelectOnScrollOffScroll() throws Exception {
+        openTestURL();
+        assertFalse("row shouldn't start out as selected",
+                isSelected(getRow(0)));
+        toggleFirstRowSelection();
+        assertTrue("row should become selected", isSelected(getRow(0)));
+
+        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", isSelected(getRow(0)));
+    }
+
+    @Test
+    public void testSelectScrollOnScrollOff() throws Exception {
+        openTestURL();
+        assertFalse("row shouldn't start out as selected",
+                isSelected(getRow(0)));
+
+        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", isSelected(getRow(0)));
+
+        toggleFirstRowSelection();
+        assertFalse("row shouldn't remain selected", isSelected(getRow(0)));
+    }
+
+    @Test
+    public void testSelectScrollOnOffScroll() throws Exception {
+        openTestURL();
+        assertFalse("row shouldn't start out as selected",
+                isSelected(getRow(0)));
+
+        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", isSelected(getRow(0)));
+    }
+
+    private void toggleFirstRowSelection() {
+        selectMenuPath("Component", "Body rows", "Select first row");
+    }
+
+    @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 TestBenchElement getRow(int i) {
+        return getGridElement().getRow(i);
+    }
+
     private void assertPrimaryStylename(String stylename) {
         assertTrue(getGridElement().getAttribute("class").contains(stylename));
 
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java
index 91a4e19886..8ea652cc74 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
 import org.openqa.selenium.WebElement;
+import org.openqa.selenium.remote.DesiredCapabilities;
 
 import com.vaadin.testbench.By;
 import com.vaadin.testbench.TestBenchElement;
@@ -42,6 +43,14 @@ public class GridClientRenderers extends MultiBrowserTest {
 
     private int latency = 0;
 
+    @Override
+    protected DesiredCapabilities getDesiredCapabilities() {
+        DesiredCapabilities c = new DesiredCapabilities(
+                super.getDesiredCapabilities());
+        c.setCapability("handlesAlerts", true);
+        return c;
+    }
+
     @Override
     protected Class getUIClass() {
         return GridClientColumnRenderers.class;
-- 
cgit v1.2.3


From 483a098979c5882f9f1c3312fe38df7f817cc397 Mon Sep 17 00:00:00 2001
From: Henrik Paul 
Date: Thu, 19 Jun 2014 11:20:03 +0300
Subject: Add connectors for server-side Renderers (#13334)

Change-Id: Id1725b12c98e661a6abfdd55adaf8dd0669ad359
---
 .../client/ui/grid/renderers/DateRenderer.java     |   6 +-
 .../ui/grid/renderers/DateRendererConnector.java   |  34 +++++
 .../ui/grid/renderers/NumberRendererConnector.java |  35 +++++
 .../renderers/UnsafeHtmlRendererConnector.java     |  53 +++++++
 .../com/vaadin/ui/components/grid/GridColumn.java  |   1 +
 .../ui/components/grid/renderers/DateRenderer.java | 150 ++++++++++++++++++++
 .../ui/components/grid/renderers/HtmlRenderer.java |  36 +++++
 .../components/grid/renderers/NumberRenderer.java  | 157 +++++++++++++++++++++
 .../ui/components/grid/renderers/TextRenderer.java |   3 +
 .../tests/components/grid/GridBasicFeatures.java   |  65 +++++++--
 10 files changed, 528 insertions(+), 12 deletions(-)
 create mode 100644 client/src/com/vaadin/client/ui/grid/renderers/DateRendererConnector.java
 create mode 100644 client/src/com/vaadin/client/ui/grid/renderers/NumberRendererConnector.java
 create mode 100644 client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java
 create mode 100644 server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java
 create mode 100644 server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java
 create mode 100644 server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java

(limited to 'uitest/src')

diff --git a/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java
index d52e97c62c..9d18ae9256 100644
--- a/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java
+++ b/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java
@@ -18,6 +18,7 @@ package com.vaadin.client.ui.grid.renderers;
 import java.util.Date;
 
 import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
 import com.google.gwt.i18n.client.TimeZone;
 import com.vaadin.client.ui.grid.FlyweightCell;
 import com.vaadin.client.ui.grid.Renderer;
@@ -30,8 +31,11 @@ import com.vaadin.client.ui.grid.Renderer;
  */
 public class DateRenderer implements Renderer {
 
-    private DateTimeFormat format = DateTimeFormat.getShortDateTimeFormat();
+    private DateTimeFormat format = DateTimeFormat
+            .getFormat(PredefinedFormat.DATE_TIME_SHORT);
 
+    // Calendar is unavailable for GWT
+    @SuppressWarnings("deprecation")
     private TimeZone timeZone = TimeZone.createTimeZone(new Date()
             .getTimezoneOffset());
 
diff --git a/client/src/com/vaadin/client/ui/grid/renderers/DateRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/DateRendererConnector.java
new file mode 100644
index 0000000000..71c7ff78e3
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/grid/renderers/DateRendererConnector.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.grid.renderers;
+
+import com.vaadin.shared.ui.Connect;
+
+/**
+ * A connector for {@link com.vaadin.ui.components.grid.renderers.DateRenderer
+ * DateRenderer}.
+ * 

+ * The server-side Renderer operates on dates, but the data is serialized as a + * string, and displayed as-is on the client side. This is to be able to support + * the server's locale. + * + * @since 7.4 + * @author Vaadin Ltd + */ +@Connect(com.vaadin.ui.components.grid.renderers.DateRenderer.class) +public class DateRendererConnector extends TextRendererConnector { + // No implementation needed +} diff --git a/client/src/com/vaadin/client/ui/grid/renderers/NumberRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/NumberRendererConnector.java new file mode 100644 index 0000000000..c698144d30 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/renderers/NumberRendererConnector.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.client.ui.grid.renderers; + +import com.vaadin.shared.ui.Connect; + +/** + * A connector for + * {@link com.vaadin.ui.components.grid.renderers.NumberRenderer NumberRenderer} + * . + *

+ * The server-side Renderer operates on numbers, but the data is serialized as a + * string, and displayed as-is on the client side. This is to be able to support + * the server's locale. + * + * @since 7.4 + * @author Vaadin Ltd + */ +@Connect(com.vaadin.ui.components.grid.renderers.NumberRenderer.class) +public class NumberRendererConnector extends TextRendererConnector { + // no implementation needed +} diff --git a/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java new file mode 100644 index 0000000000..c0dcf0505d --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.renderers; + +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Renderer; +import com.vaadin.shared.ui.Connect; + +/** + * A connector for {@link UnsafeHtmlRenderer} + * + * @since 7.4 + * @author Vaadin Ltd + */ +@Connect(com.vaadin.ui.components.grid.renderers.HtmlRenderer.class) +public class UnsafeHtmlRendererConnector extends + AbstractRendererConnector { + + public class UnsafeHtmlRenderer implements Renderer { + @Override + public void render(FlyweightCell cell, String data) { + cell.getElement().setInnerHTML(data); + } + } + + @Override + public UnsafeHtmlRenderer getRenderer() { + return (UnsafeHtmlRenderer) super.getRenderer(); + } + + @Override + protected UnsafeHtmlRenderer createRenderer() { + return new UnsafeHtmlRenderer(); + } + + @Override + public Class getType() { + return String.class; + } +} diff --git a/server/src/com/vaadin/ui/components/grid/GridColumn.java b/server/src/com/vaadin/ui/components/grid/GridColumn.java index 634526ea7c..cadd621948 100644 --- a/server/src/com/vaadin/ui/components/grid/GridColumn.java +++ b/server/src/com/vaadin/ui/components/grid/GridColumn.java @@ -239,6 +239,7 @@ public class GridColumn implements Serializable { * the renderer to use * @throws IllegalArgumentException * if no compatible converter could be found + * * @see VaadinSession#getConverterFactory() * @see ConverterUtil#getConverter(Class, Class, VaadinSession) * @see #setConverter(Converter) diff --git a/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java new file mode 100644 index 0000000000..8c062252f2 --- /dev/null +++ b/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java @@ -0,0 +1,150 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.grid.renderers; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * A renderer for presenting date values. + * + * @since 7.4 + * @author Vaadin Ltd + */ +public class DateRenderer extends AbstractRenderer { + private final Locale locale; + private final String formatString; + private final DateFormat dateFormat; + + /** + * Creates a new date renderer. + *

+ * The renderer is configured to render with the {@link Date#toString()} + * representation for the default locale. + */ + public DateRenderer() { + this(Locale.getDefault()); + } + + /** + * Creates a new date renderer. + *

+ * The renderer is configured to render with the {@link Date#toString()} + * representation for the given locale. + * + * @param locale + * the locale in which to present dates + * @throws IllegalArgumentException + * if {@code locale} is {@code null} + */ + public DateRenderer(Locale locale) throws IllegalArgumentException { + this("%s", locale); + } + + /** + * Creates a new date renderer. + *

+ * The renderer is configured to render with the given string format, as + * displayed in the default locale. + * + * @param formatString + * the format string with which to format the date + * @throws IllegalArgumentException + * if {@code formatString} is {@code null} + * @see Format + * String Syntax + */ + public DateRenderer(String formatString) throws IllegalArgumentException { + this(formatString, Locale.getDefault()); + } + + /** + * Creates a new date renderer. + *

+ * The renderer is configured to render with the given string format, as + * displayed in the given locale. + * + * @param formatString + * the format string to format the date with + * @param locale + * the locale to use + * @throws IllegalArgumentException + * if either argument is {@code null} + * @see Format + * String Syntax + */ + public DateRenderer(String formatString, Locale locale) + throws IllegalArgumentException { + super(Date.class); + + if (formatString == null) { + throw new IllegalArgumentException("format string may not be null"); + } + + if (locale == null) { + throw new IllegalArgumentException("locale may not be null"); + } + + this.locale = locale; + this.formatString = formatString; + dateFormat = null; + } + + /** + * Creates a new date renderer. + *

+ * The renderer is configured to render with he given date format. + * + * @param dateFormat + * the date format to use when rendering dates + * @throws IllegalArgumentException + * if {@code dateFormat} is {@code null} + */ + public DateRenderer(DateFormat dateFormat) throws IllegalArgumentException { + super(Date.class); + if (dateFormat == null) { + throw new IllegalArgumentException("date format may not be null"); + } + + locale = null; + formatString = null; + this.dateFormat = dateFormat; + } + + @Override + public String encode(Date value) { + if (dateFormat != null) { + return dateFormat.format(value); + } else { + return String.format(locale, formatString, value); + } + } + + @Override + public String toString() { + final String fieldInfo; + if (dateFormat != null) { + fieldInfo = "dateFormat: " + dateFormat.toString(); + } else { + fieldInfo = "locale: " + locale + ", formatString: " + formatString; + } + + return String.format("%s [%s]", getClass().getSimpleName(), fieldInfo); + } +} diff --git a/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java new file mode 100644 index 0000000000..bf5024159f --- /dev/null +++ b/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.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.ui.components.grid.renderers; + +/** + * A renderer for presenting HTML content. + * + * @since 7.4 + * @author Vaadin Ltd + */ +public class HtmlRenderer extends AbstractRenderer { + /** + * Creates a new HTML renderer. + */ + public HtmlRenderer() { + super(String.class); + } + + @Override + public String encode(String value) { + return value; + } +} diff --git a/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java new file mode 100644 index 0000000000..bdfe23c366 --- /dev/null +++ b/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java @@ -0,0 +1,157 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.grid.renderers; + +import java.text.DecimalFormat; +import java.util.Locale; + +/** + * A renderer for presenting number values. + * + * @since 7.4 + * @author Vaadin Ltd + */ +public class NumberRenderer extends AbstractRenderer { + private final Locale locale; + private final DecimalFormat decimalFormat; + private final String formatString; + + /** + * Creates a new number renderer. + *

+ * The renderer is configured to render with the number's natural string + * representation in the default locale. + */ + public NumberRenderer() { + this(Locale.getDefault()); + } + + /** + * Creates a new number renderer. + *

+ * The renderer is configured to render the number as defined with the given + * decimal format. + * + * @param decimalFormat + * the decimal format with which to display numbers + * @throws IllegalArgumentException + * if {@code decimalFormat} is {@code null} + */ + public NumberRenderer(DecimalFormat decimalFormat) + throws IllegalArgumentException { + super(Number.class); + + if (decimalFormat == null) { + throw new IllegalArgumentException("Decimal format may not be null"); + } + + locale = null; + this.decimalFormat = decimalFormat; + formatString = null; + } + + /** + * Creates a new number renderer. + *

+ * The renderer is configured to render with the number's natural string + * representation in the given locale. + * + * @param locale + * the locale in which to display numbers + * @throws IllegalArgumentException + * if {@code locale} is {@code null} + */ + public NumberRenderer(Locale locale) throws IllegalArgumentException { + this("%s", locale); + } + + /** + * Creates a new number renderer. + *

+ * The renderer is configured to render with the given format string in the + * default locale. + * + * @param formatString + * the format string with which to format the number + * @throws IllegalArgumentException + * if {@code formatString} is {@code null} + * @see Format + * String Syntax + */ + public NumberRenderer(String formatString) throws IllegalArgumentException { + this(formatString, Locale.getDefault()); + } + + /** + * Creates a new number renderer. + *

+ * The renderer is configured to render with the given format string in the + * given locale. + * + * @param formatString + * the format string with which to format the number + * @param locale + * the locale in which to present numbers + * @throws IllegalArgumentException + * if either argument is {@code null} + * @see Format + * String Syntax + */ + public NumberRenderer(String formatString, Locale locale) { + super(Number.class); + + if (formatString == null) { + throw new IllegalArgumentException("Format string may not be null"); + } + + if (locale == null) { + throw new IllegalArgumentException("Locale may not be null"); + } + + this.locale = locale; + decimalFormat = null; + this.formatString = formatString; + } + + @Override + public String encode(Number value) { + if (formatString != null && locale != null) { + return String.format(locale, formatString, value); + } else if (decimalFormat != null) { + return decimalFormat.format(value); + } else { + throw new IllegalStateException(String.format("Internal bug: " + + "%s is in an illegal state: " + + "[locale: %s, decimalFormat: %s, formatString: %s]", + getClass().getSimpleName(), locale, decimalFormat, + formatString)); + } + } + + @Override + public String toString() { + final String fieldInfo; + if (decimalFormat != null) { + fieldInfo = "decimalFormat: " + decimalFormat.toString(); + } else { + fieldInfo = "locale: " + locale + ", formatString: " + formatString; + } + + return String.format("%s [%s]", getClass().getSimpleName(), fieldInfo); + } +} diff --git a/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java index 28aae27085..e375d5913b 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java @@ -23,6 +23,9 @@ package com.vaadin.ui.components.grid.renderers; */ public class TextRenderer extends AbstractRenderer { + /** + * Creates a new text renderer + */ public TextRenderer() { super(String.class); } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index c6597ef23b..07fb80e0dd 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -16,9 +16,13 @@ package com.vaadin.tests.components.grid; import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; @@ -28,6 +32,9 @@ import com.vaadin.ui.components.grid.ColumnGroup; import com.vaadin.ui.components.grid.ColumnGroupRow; import com.vaadin.ui.components.grid.Grid; import com.vaadin.ui.components.grid.GridColumn; +import com.vaadin.ui.components.grid.renderers.DateRenderer; +import com.vaadin.ui.components.grid.renderers.HtmlRenderer; +import com.vaadin.ui.components.grid.renderers.NumberRenderer; /** * Tests the basic features like columns, footers and headers @@ -37,15 +44,15 @@ import com.vaadin.ui.components.grid.GridColumn; */ public class GridBasicFeatures extends AbstractComponentTest { - private final int COLUMNS = 10; + private static final int MANUALLY_FORMATTED_COLUMNS = 3; + private static final int COLUMNS = 10; + private static final int ROWS = 1000; private int columnGroupRows = 0; - - private final int ROWS = 1000; - private IndexedContainer ds; @Override + @SuppressWarnings("unchecked") protected Grid constructComponent() { // Build data source @@ -58,21 +65,57 @@ public class GridBasicFeatures extends AbstractComponentTest { } }; - for (int col = 0; col < COLUMNS; col++) { - ds.addContainerProperty(getColumnProperty(col), String.class, ""); + { + 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, ""); } - for (int row = 0; row < ROWS; row++) { - Item item = ds.addItem(Integer.valueOf(row)); - for (int col = 0; col < COLUMNS; col++) { - item.getItemProperty(getColumnProperty(col)).setValue( - "(" + row + ", " + col + ")"); + { + 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(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( + "" + row + ""); } } // 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()); + } + // Add footer values (header values are automatically created) for (int col = 0; col < COLUMNS; col++) { grid.getColumn(getColumnProperty(col)).setFooterCaption( -- cgit v1.2.3 From cd3bf156c1682e17bf6474b77057eebd6521d34a Mon Sep 17 00:00:00 2001 From: Patrik Lindström Date: Mon, 30 Jun 2014 15:53:04 +0300 Subject: Implement Grid client-side ListSorter (#13334) Change-Id: I51e6b56a00ac45185be98d6c62c3b0ee7494c8f4 --- .../client/ui/grid/datasources/ListSorter.java | 177 +++++++++++++++++++++ .../tests/components/grid/GridClientRenderers.java | 53 +++++- .../grid/GridClientColumnRendererConnector.java | 52 ++++++ .../client/grid/GridClientColumnRendererRpc.java | 10 ++ .../server/grid/GridClientColumnRenderers.java | 34 +++- 5 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/datasources/ListSorter.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/datasources/ListSorter.java b/client/src/com/vaadin/client/ui/grid/datasources/ListSorter.java new file mode 100644 index 0000000000..81ea3efd92 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/datasources/ListSorter.java @@ -0,0 +1,177 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.datasources; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.gwt.event.shared.HandlerRegistration; +import com.vaadin.client.data.DataSource; +import com.vaadin.client.ui.grid.Grid; +import com.vaadin.client.ui.grid.GridColumn; +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.grid.SortDirection; + +/** + * Provides sorting facility from Grid for the {@link ListDataSource} in-memory + * data source. + * + * @since 7.4 + * @author Vaadin Ltd + * @param + * Grid row data type + */ +public class ListSorter { + + private Grid grid; + private Map, Comparator> comparators; + private HandlerRegistration sortHandlerRegistration; + + public ListSorter(Grid grid) { + + if (grid == null) { + throw new IllegalArgumentException("Grid can not be null"); + } + + this.grid = grid; + comparators = new HashMap, Comparator>(); + + sortHandlerRegistration = grid + .addSortHandler(new SortEventHandler() { + @Override + public void sort(SortEvent event) { + ListSorter.this.sort(event.getOrder()); + } + }); + } + + /** + * Detach this Sorter from the Grid. This unregisters the sort event handler + * which was used to apply sorting to the ListDataSource. + */ + public void removeFromGrid() { + sortHandlerRegistration.removeHandler(); + } + + /** + * Assign or remove a comparator for a column. This comparator method, if + * defined, is always used in favour of 'natural' comparison of objects + * (i.e. the compareTo of objects implementing the Comparable interface, + * which includes all standard data classes like String, Number derivatives + * and Dates). Any existing comparator can be removed by passing in a + * non-null GridColumn and a null Comparator. + * + * @param column + * a grid column. May not be null. + * @param comparator + * comparator method for the values returned by the grid column. + * If null, any existing comparator is removed. + */ + public void setComparator(GridColumn column, + Comparator comparator) { + if (column == null) { + throw new IllegalArgumentException( + "Column reference can not be null"); + } + if (comparator == null) { + comparators.remove(column); + } else { + comparators.put(column, comparator); + } + } + + /** + * Retrieve the comparator assigned for a specific grid column. + * + * @param column + * a grid column. May not be null. + * @return a comparator, or null if no comparator for the specified grid + * column has been set. + */ + @SuppressWarnings("unchecked") + public Comparator getComparator(GridColumn column) { + if (column == null) { + throw new IllegalArgumentException( + "Column reference can not be null"); + } + return (Comparator) comparators.get(column); + } + + /** + * Remove all comparator mappings. Useful if the data source has changed but + * this Sorter is being re-used. + */ + public void clearComparators() { + comparators.clear(); + } + + /** + * Apply sorting to the current ListDataSource. + * + * @param order + * the sort order list provided by the grid sort event + */ + private void sort(final List order) { + DataSource ds = grid.getDataSource(); + if (!(ds instanceof ListDataSource)) { + throw new IllegalStateException("Grid " + grid + + " data source is not a ListDataSource!"); + } + + ((ListDataSource) ds).sort(new Comparator() { + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + public int compare(T a, T b) { + + for (SortOrder o : order) { + + GridColumn column = o.getColumn(); + Comparator cmp = ListSorter.this.comparators.get(column); + int result = 0; + Object value_a = column.getValue(a); + Object value_b = column.getValue(b); + if (cmp != null) { + result = cmp.compare(value_a, value_b); + } else { + if (!(value_a instanceof Comparable)) { + throw new IllegalStateException("Column " + column + + " has no assigned comparator and value " + + value_a + " isn't naturally comparable"); + } + result = ((Comparable) value_a).compareTo(value_b); + } + + if (result != 0) { + return o.getDirection() == SortDirection.ASCENDING ? result + : -result; + } + } + + if (order.size() > 0) { + return order.get(0).getDirection() == SortDirection.ASCENDING ? a + .hashCode() - b.hashCode() + : b.hashCode() - a.hashCode(); + } + return a.hashCode() - b.hashCode(); + } + }); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index 8ea652cc74..0cb5dea8f8 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -175,7 +175,8 @@ public class GridClientRenderers extends MultiBrowserTest { public void testSortingEvent() throws Exception { openTestURL(); - $(NativeButtonElement.class).caption("Trigger sorting").first().click(); + $(NativeButtonElement.class).caption("Trigger sorting event").first() + .click(); sleep(1000); String consoleText = $(LabelElement.class).id("testDebugConsole") @@ -186,6 +187,56 @@ public class GridClientRenderers extends MultiBrowserTest { } + @Test + public void testListSorter() throws Exception { + openTestURL(); + sleep(1000); + + $(NativeButtonElement.class).caption("Shuffle").first().click(); + sleep(1000); + + 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(); + sleep(1000); + + for (int i = 1, l = 70; i < l; ++i) { + + if (i == 19) { + System.err.println("foo"); + } + + 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); + } + } + } + private GridElement getGrid() { return $(MyClientGridElement.class).first(); } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index 95052917c1..48aba1d2dd 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -16,6 +16,7 @@ package com.vaadin.tests.widgetset.client.grid; import java.util.ArrayList; +import java.util.Comparator; import java.util.Date; import java.util.List; @@ -35,6 +36,7 @@ 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; @@ -198,6 +200,56 @@ public class GridClientColumnRendererConnector extends public void triggerClientSorting() { getWidget().sort(Sort.by(getWidget().getColumn(0))); } + + @Override + @SuppressWarnings("unchecked") + public void triggerClientSortingTest() { + Grid grid = getWidget(); + ListSorter sorter = new ListSorter(grid); + + // Make sorter sort the numbers in natural order + sorter.setComparator( + (GridColumn) grid.getColumn(0), + new Comparator() { + @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 grid = getWidget(); + ListSorter shuffler = new ListSorter( + grid); + + // Make shuffler return random order + shuffler.setComparator( + (GridColumn) grid.getColumn(0), + new Comparator() { + @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(); + } }); } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java index ade239466e..90eee9e1c6 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererRpc.java @@ -35,4 +35,14 @@ public interface GridClientColumnRendererRpc extends ClientRpc { * Used for client-side sorting API test */ void triggerClientSorting(); + + /** + * @since + */ + void triggerClientSortingTest(); + + /** + * @since + */ + void shuffle(); } diff --git a/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java b/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java index d41370cc02..db931888bc 100644 --- a/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java +++ b/uitest/src/com/vaadin/tests/widgetset/server/grid/GridClientColumnRenderers.java @@ -65,6 +65,20 @@ public class GridClientColumnRenderers extends UI { public void triggerClientSorting() { rpc().triggerClientSorting(); } + + /** + * @since + */ + public void triggerClientSortingTest() { + rpc().triggerClientSortingTest(); + } + + /** + * @since + */ + public void shuffle() { + rpc().shuffle(); + } } @Override @@ -104,7 +118,16 @@ public class GridClientColumnRenderers extends UI { }); controls.addComponent(detachAttachBtn); - NativeButton sortButton = new NativeButton("Trigger sorting"); + 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) { @@ -113,6 +136,15 @@ public class GridClientColumnRenderers extends UI { }); 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"); -- cgit v1.2.3 From fdba3d43f594bb0236df022f505b64f4970885e5 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Fri, 27 Jun 2014 12:55:45 +0300 Subject: Clean up test code for selection column (#13334) Change-Id: I98963a367f05c39ad6e185ebf8a1d903efa686a2 --- client/src/com/vaadin/client/ui/grid/Grid.java | 48 +++++++++------------- .../com/vaadin/client/ui/grid/GridConnector.java | 45 ++++++++++++++++++-- server/src/com/vaadin/ui/components/grid/Grid.java | 7 ---- .../src/com/vaadin/shared/ui/grid/GridState.java | 4 -- .../tests/components/grid/GridBasicFeatures.java | 8 ---- 5 files changed, 61 insertions(+), 51 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 9a75b37c42..c223f8786f 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -123,9 +123,9 @@ public class Grid extends Composite implements @Override public void setFooterCaption(String caption) { - if (initDone) { - throw new UnsupportedOperationException( - "The selection column is read only"); + if (!SharedUtil.equals(caption, getFooterCaption()) && initDone) { + throw new UnsupportedOperationException("The selection " + + "column cannot be modified after init"); } else { super.setFooterCaption(caption); } @@ -133,9 +133,9 @@ public class Grid extends Composite implements @Override public void setFooterRenderer(Renderer renderer) { - if (initDone) { - throw new UnsupportedOperationException( - "The selection column is read only"); + if (!SharedUtil.equals(renderer, getFooterRenderer()) && initDone) { + throw new UnsupportedOperationException("The selection " + + "column cannot be modified after init"); } else { super.setFooterRenderer(renderer); } @@ -143,9 +143,9 @@ public class Grid extends Composite implements @Override public void setHeaderCaption(String caption) { - if (initDone) { - throw new UnsupportedOperationException( - "The selection column is read only"); + if (!SharedUtil.equals(caption, getHeaderCaption()) && initDone) { + throw new UnsupportedOperationException("The selection " + + "column cannot be modified after init"); } else { super.setHeaderCaption(caption); } @@ -153,9 +153,9 @@ public class Grid extends Composite implements @Override public void setHeaderRenderer(Renderer renderer) { - if (initDone) { - throw new UnsupportedOperationException( - "The selection column is read only"); + if (!SharedUtil.equals(renderer, getHeaderRenderer()) && initDone) { + throw new UnsupportedOperationException("The selection " + + "column cannot be modified after init"); } else { super.setHeaderRenderer(renderer); } @@ -163,9 +163,9 @@ public class Grid extends Composite implements @Override public void setVisible(boolean visible) { - if (initDone) { - throw new UnsupportedOperationException( - "The selection column is read only"); + if (!visible && initDone) { + throw new UnsupportedOperationException("The selection " + + "column cannot be modified after init"); } else { super.setVisible(visible); } @@ -173,9 +173,9 @@ public class Grid extends Composite implements @Override public void setWidth(int pixels) { - if (initDone) { - throw new UnsupportedOperationException( - "The selection column is read only"); + if (pixels != getWidth() && initDone) { + throw new UnsupportedOperationException("The selection " + + "column cannot be modified after init"); } else { super.setWidth(pixels); } @@ -2199,15 +2199,6 @@ public class Grid extends Composite implements } } - /* TODO remove before final */ - public void setSelectionCheckboxes(boolean set) { - if (set) { - setSelectColumnRenderer(selectionModel.getSelectionColumnRenderer()); - } else { - setSelectColumnRenderer(null); - } - } - /** * Accesses the package private method Widget#setParent() * @@ -2239,7 +2230,8 @@ public class Grid extends Composite implements this.selectionModel = selectionModel; selectionModel.setGrid(this); - + setSelectColumnRenderer(this.selectionModel + .getSelectionColumnRenderer()); } /** diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 31e52b1c1c..59b8c4047c 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -234,6 +234,9 @@ public class GridConnector extends AbstractComponentConnector { purgeRemovedColumns(); int currentColumns = getWidget().getColumnCount(); + if (getWidget().getSelectionModel().getSelectionColumnRenderer() != null) { + currentColumns--; + } // Add new columns for (int columnIndex = currentColumns; columnIndex < totalColumns; columnIndex++) { @@ -289,11 +292,24 @@ public class GridConnector extends AbstractComponentConnector { * @param columnIndex * The index of the column to update */ - private void updateColumnFromStateChangeEvent(int columnIndex) { - GridColumn column = getWidget().getColumn(columnIndex); + private void updateColumnFromStateChangeEvent(final int columnIndex) { + /* + * We use the widget column index here instead of the given column + * index. SharedState contains information only about the explicitly + * defined columns, while the widget counts the selection column as an + * explicit one. + */ + GridColumn column = getWidget().getColumn( + getWidgetColumnIndex(columnIndex)); + GridColumnState columnState = getState().columns.get(columnIndex); updateColumnFromState(column, columnState); + assert column instanceof CustomGridColumn : "column at index " + + columnIndex + " is not a " + + CustomGridColumn.class.getSimpleName() + ", but a " + + column.getClass().getSimpleName(); + if (columnState.rendererConnector != ((CustomGridColumn) column) .getRendererConnector()) { throw new UnsupportedOperationException( @@ -314,8 +330,15 @@ public class GridConnector extends AbstractComponentConnector { ((AbstractRendererConnector) state.rendererConnector)); columnIdToColumn.put(state.id, column); - // Adds a column to grid, and registers Grid with the column. - getWidget().addColumn(column, columnIndex); + /* + * Adds a column to grid, and registers Grid with the column. + * + * We use the widget column index here instead of the given column + * index. SharedState contains information only about the explicitly + * defined columns, while the widget counts the selection column as an + * explicit one. + */ + getWidget().addColumn(column, getWidgetColumnIndex(columnIndex)); /* * Have to update state _after_ the column has been added to the grid as @@ -328,6 +351,20 @@ public class GridConnector extends AbstractComponentConnector { updateColumnFromState(column, state); } + /** + * If we have a selection column renderer, we need to offset the index by + * one when referring to the column index in the widget. + */ + private int getWidgetColumnIndex(final int columnIndex) { + Renderer selectionColumnRenderer = getWidget() + .getSelectionModel().getSelectionColumnRenderer(); + int widgetColumnIndex = columnIndex; + if (selectionColumnRenderer != null) { + widgetColumnIndex++; + } + return widgetColumnIndex; + } + /** * Updates the column values from a state * diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index bc6a69e850..21cb50154f 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -1048,13 +1048,6 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { SELECTION_CHANGE_METHOD); } - /** - * FIXME remove once selection mode communication is done. only for testing. - */ - public void setSelectionCheckboxes(boolean value) { - getState().selectionCheckboxes = value; - } - /** * A shortcut for * {@link #datasourceExtension}.{@link com.vaadin.data.RpcDataProviderExtension#getKeyMapper() getKeyMapper()} diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index d223d64e7e..6ca0021817 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -92,10 +92,6 @@ public class GridState extends AbstractComponentState { @DelegateToWidget public HeightMode heightMode = HeightMode.CSS; - /** FIXME remove once selection mode communcation is done. only for testing. */ - @DelegateToWidget - public boolean selectionCheckboxes; - // instantiated just to avoid NPEs public List selectedKeys = new ArrayList(); diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index 07fb80e0dd..cfe1d0c00d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -190,14 +190,6 @@ public class GridBasicFeatures extends AbstractComponentTest { protected void createColumnActions() { createCategory("Columns", null); - createBooleanAction("Selection controls", "Columns", false, - new Command() { - @Override - public void execute(Grid grid, Boolean value, Object data) { - grid.setSelectionCheckboxes(value); - } - }); - for (int c = 0; c < COLUMNS; c++) { createCategory(getColumnProperty(c), "Columns"); -- cgit v1.2.3 From 1f94f03f56182697fda5c79ff42c492f26a8767b Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Mon, 30 Jun 2014 17:37:51 +0300 Subject: Client now recognizes server-side selection model changes. (#13334) Change-Id: Ic42e0e96871620fde6b9ce17dd5b487b1d6b8370 --- .../com/vaadin/client/ui/grid/GridConnector.java | 17 ++++++++++ server/src/com/vaadin/ui/components/grid/Grid.java | 13 ++++++++ .../src/com/vaadin/shared/ui/grid/GridState.java | 37 ++++++++++++++++++++++ .../tests/components/grid/GridBasicFeatures.java | 14 ++++++++ 4 files changed, 81 insertions(+) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 59b8c4047c..ee1cc0ee75 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -25,10 +25,12 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.logging.Logger; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONValue; +import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.data.RpcDataSourceConnector.RpcDataSource; import com.vaadin.client.ui.AbstractComponentConnector; @@ -43,6 +45,7 @@ import com.vaadin.shared.ui.grid.GridClientRpc; import com.vaadin.shared.ui.grid.GridColumnState; import com.vaadin.shared.ui.grid.GridServerRpc; import com.vaadin.shared.ui.grid.GridState; +import com.vaadin.shared.ui.grid.GridState.SharedSelectionMode; import com.vaadin.shared.ui.grid.ScrollDestination; /** @@ -444,4 +447,18 @@ public class GridConnector extends AbstractComponentConnector { this.dataSource = dataSource; getWidget().setDataSource(this.dataSource); } + + @OnStateChange("selectionMode") + private void onSelectionModeChange() { + SharedSelectionMode mode = getState().selectionMode; + if (mode == null) { + getLogger().warning("ignored mode change"); + return; + } + getLogger().warning(mode.toString()); + } + + private Logger getLogger() { + return Logger.getLogger(getClass().getName()); + } } diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 21cb50154f..d20e4efe8b 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -44,6 +44,7 @@ import com.vaadin.shared.ui.grid.GridClientRpc; import com.vaadin.shared.ui.grid.GridColumnState; import com.vaadin.shared.ui.grid.GridServerRpc; import com.vaadin.shared.ui.grid.GridState; +import com.vaadin.shared.ui.grid.GridState.SharedSelectionMode; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.ui.AbstractComponent; @@ -830,6 +831,18 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { this.selectionModel = selectionModel; this.selectionModel.setGrid(this); this.selectionModel.reset(); + + if (selectionModel.getClass().equals(SingleSelectionModel.class)) { + getState().selectionMode = SharedSelectionMode.SINGLE; + } else if (selectionModel.getClass().equals( + MultiSelectionModel.class)) { + getState().selectionMode = SharedSelectionMode.MULTI; + } else if (selectionModel.getClass().equals(NoSelectionModel.class)) { + getState().selectionMode = SharedSelectionMode.NONE; + } else { + throw new UnsupportedOperationException("Grid currently " + + "supports only its own bundled selection models"); + } } } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index 6ca0021817..3dcf7764ac 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -30,6 +30,42 @@ import com.vaadin.shared.annotations.DelegateToWidget; */ public class GridState extends AbstractComponentState { + /** + * A description of which of the three bundled SelectionModels is currently + * in use. + *

+ * Used as a data transfer object instead of the client/server ones, because + * they don't know about each others classes. + * + * @see com.vaadin.ui.components.grid.Grid.SelectionMode + * @see com.vaadin.client.ui.grid.Grid.SelectionMode + */ + public enum SharedSelectionMode { + /** + * Representation of a single selection mode + * + * @see com.vaadin.ui.components.grid.Grid.SelectionMode#SINGLE + * @see com.vaadin.client.ui.grid.Grid.SelectionMode#SINGLE + */ + SINGLE, + + /** + * Representation of a multiselection mode + * + * @see com.vaadin.ui.components.grid.Grid.SelectionMode#MULTI + * @see com.vaadin.client.ui.grid.Grid.SelectionMode#MULTI + */ + MULTI, + + /** + * Representation of a no-selection mode + * + * @see com.vaadin.ui.components.grid.Grid.SelectionMode#NONE + * @see com.vaadin.client.ui.grid.Grid.SelectionMode#NONE + */ + NONE; + } + /** * The default value for height-by-rows for both GWT widgets * {@link com.vaadin.ui.components.grid Grid} and @@ -95,4 +131,5 @@ public class GridState extends AbstractComponentState { // instantiated just to avoid NPEs public List selectedKeys = new ArrayList(); + public SharedSelectionMode selectionMode; } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index cfe1d0c00d..6af229bd28 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -31,6 +31,7 @@ import com.vaadin.tests.components.AbstractComponentTest; import com.vaadin.ui.components.grid.ColumnGroup; import com.vaadin.ui.components.grid.ColumnGroupRow; 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.renderers.DateRenderer; import com.vaadin.ui.components.grid.renderers.HtmlRenderer; @@ -159,6 +160,19 @@ public class GridBasicFeatures extends AbstractComponentTest { } }, primaryStyleNames.get("v-grid")); + + LinkedHashMap selectionModes = new LinkedHashMap(); + selectionModes.put("single", SelectionMode.SINGLE); + selectionModes.put("multi", SelectionMode.MULTI); + selectionModes.put("none", SelectionMode.NONE); + createSelectAction("Selection mode", "State", selectionModes, "multi", + new Command() { + @Override + public void execute(Grid grid, SelectionMode selectionMode, + Object data) { + grid.setSelectionMode(selectionMode); + } + }); } protected void createHeaderActions() { -- cgit v1.2.3 From e845b4128a0ddf5b488f5c5cf5e0ea33c5b393dc Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Wed, 4 Jun 2014 13:54:41 +0300 Subject: Make Grid scroll as the selection drag happens near an edge. (#13334) Change-Id: Id5188cc090e181deb2128933236d39d7b418c16a --- client/src/com/vaadin/client/ui/grid/Grid.java | 19 + .../ui/grid/selection/MultiSelectionRenderer.java | 452 ++++++++++++++++----- .../tests/components/grid/GridBasicFeatures.java | 20 +- 3 files changed, 398 insertions(+), 93 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index c223f8786f..da5adfc34a 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -1959,6 +1959,25 @@ public class Grid extends Composite implements ScrollDestination.END); } + /** + * Sets the vertical scroll offset. + * + * @param px + * the number of pixels this grid should be scrolled down + */ + public void setScrollTop(double px) { + escalator.setScrollTop(px); + } + + /** + * Gets the vertical scroll offset + * + * @return the number of pixels this grid is scrolled down + */ + public double getScrollTop() { + return escalator.getScrollTop(); + } + private static final Logger getLogger() { return Logger.getLogger(Grid.class.getName()); } diff --git a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java index 53b0d064ab..3754c51f18 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java @@ -18,12 +18,14 @@ package com.vaadin.client.ui.grid.selection; import java.util.Collection; import java.util.HashSet; +import com.google.gwt.animation.client.AnimationScheduler; +import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback; +import com.google.gwt.animation.client.AnimationScheduler.AnimationHandle; import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.InputElement; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.TableElement; -import com.google.gwt.dom.client.Touch; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; @@ -38,63 +40,67 @@ import com.vaadin.client.ui.grid.renderers.ComplexRenderer; /* This class will probably not survive the final merge of all selection functionality. */ public class MultiSelectionRenderer extends ComplexRenderer { + /** The size of the autoscroll area, both top and bottom. */ + private static final int SCROLL_AREA_GRADIENT_PX = 100; + + /** The maximum number of pixels per second to autoscroll. */ + private static final int SCROLL_TOP_SPEED_PX_SEC = 500; + + /** + * The minimum area where the grid doesn't scroll while the pointer is + * pressed. + */ + private static final int MIN_NO_AUTOSCROLL_AREA_PX = 50; + + /** + * This class's main objective is to listen when to stop autoscrolling, and + * make sure everything stops accordingly. + */ private class TouchEventHandler implements NativePreviewHandler { @Override public void onPreviewNativeEvent(final NativePreviewEvent event) { switch (event.getTypeInt()) { - case Event.ONTOUCHSTART: - case Event.ONTOUCHMOVE: - case Event.ONTOUCHEND: - case Event.ONTOUCHCANCEL: - final Element targetElement = Element.as(event.getNativeEvent() - .getEventTarget()); - if (isInFirstColumn(targetElement)) { - dispatchTouchEvent(event); - event.cancel(); + case Event.ONTOUCHSTART: { + if (event.getNativeEvent().getTouches().length() == 1) { + /* + * Something has dropped a touchend/touchcancel and the + * scroller is most probably running amok. Let's cancel it + * and pretend that everything's going as expected + * + * Because this is a preview, this code is run before the + * event handler in MultiSelectionRenderer.onBrowserEvent. + * Therefore, we can simply kill everything and let that + * method restart things as they should. + */ + autoScrollHandler.stop(); + + /* + * Related TODO: investigate why iOS seems to ignore a + * touchend/touchcancel when frames are dropped, and/or if + * something can be done about that. + */ } break; } - } - - private void dispatchTouchEvent(final NativePreviewEvent event) { - final NativeEvent nativeEvent = event.getNativeEvent(); - final int currentRow; - if (event.getTypeInt() == Event.ONTOUCHSTART - || event.getTypeInt() == Event.ONTOUCHMOVE) { - final Element touchCurrentElement = findTouchCurrentElement(nativeEvent); - currentRow = getLogicalRowIndex(touchCurrentElement); - } else { - currentRow = -1; - } - - switch (event.getTypeInt()) { - case Event.ONTOUCHSTART: - selectionHandler.onSelectionStart(currentRow); - break; case Event.ONTOUCHMOVE: - selectionHandler.onSelectionMove(currentRow); + event.cancel(); break; + case Event.ONTOUCHEND: - selectionHandler.onSelectionEnd(); - removeNativeHandler(); - break; case Event.ONTOUCHCANCEL: - selectionHandler.onSelectionEnd(); - removeNativeHandler(); + /* + * Remember: targetElement is always where touchstart started, + * not where the finger is pointing currently. + */ + final Element targetElement = Element.as(event.getNativeEvent() + .getEventTarget()); + if (isInFirstColumn(targetElement)) { + removeNativeHandler(); + event.cancel(); + } break; - default: - throw new UnsupportedOperationException( - "Internal error: unexpected event type slipped through into our logic: " - + event); } - event.cancel(); - } - - private Element findTouchCurrentElement(final NativeEvent nativeEvent) { - final Touch touch = nativeEvent.getTouches().get(0); - return Util.getElementFromPoint(touch.getClientX(), - touch.getClientY()); } private boolean isInFirstColumn(final Element element) { @@ -123,45 +129,314 @@ public class MultiSelectionRenderer extends ComplexRenderer { } } - private class SelectionHandler { - /** The row index that is currently/last being manipulated. */ - private int currentRow = -1; + /** + * This class's responsibility is to + *

    + *
  • scroll the table while a pointer is kept in a scrolling zone and + *
  • select rows whenever a pointer is "activated" on a selection cell + *
+ *

+ * Techical note: This class is an AnimationCallback because we + * need a timer: when the finger is kept in place while the grid scrolls, we + * still need to be able to make new selections. So, instead of relying on + * events (which won't be fired, since the pointer isn't necessarily + * moving), we do this check on each frame while the pointer is "active" + * (mouse is pressed, finger is on screen). + */ + private class AutoScrollerAndSelector implements AnimationCallback { + + /** + * If the acceleration gradient area is smaller than this, autoscrolling + * will be disabled (it becomes too quick to accelerate to be usable). + */ + private static final int GRADIENT_MIN_THRESHOLD_PX = 10; + + /** + * The lowest y-coordinate on the {@link Event#getClientY() client} from + * where we need to start scrolling towards the top. + */ + private final int topBound; + + /** + * The highest y-coordinate on the {@link Event#getClientY() client} + * from where we need to scrolling towards the bottom. + */ + private final int bottomBound; + + /** + * true if the pointer is selecting, false if + * the pointer is deselecting. + */ + private final boolean selectionPaint; /** - * The selection mode that we are currently painting. - *

    - *
  • true == selection painting - *
  • false == deselection painting - *
- * This value's meaning is undefined while {@link #selectionInProgress} - * is false. + * The area where the selection acceleration takes place. If < + * {@link #GRADIENT_MIN_THRESHOLD_PX}, autoscrolling is disabled */ - private boolean selectionPaint = false; + private final int gradientArea; + + /** + * The number of pixels per seconds we currently are scrolling (negative + * is towards the top, positive is towards the bottom). + */ + private double scrollSpeed = 0; + + private double prevTimestamp = 0; + + /** + * This field stores fractions of pixels to scroll, to make sure that + * we're able to scroll less than one px per frame. + */ + private double pixelsToScroll = 0.0d; + + /** Should this animator be running. */ + private boolean running = false; - /** Whether we are painting currently or not. */ - private boolean paintingInProgress = false; + /** The handle in which this instance is running. */ + private AnimationHandle handle; - public void onSelectionStart(final int logicalRowIndex) { - paintingInProgress = true; - currentRow = logicalRowIndex; - selectionPaint = !isSelected(currentRow); - setSelected(currentRow, selectionPaint); + /** The pointer's pageX coordinate. */ + private int pageX; + + /** The pointer's pageY coordinate. */ + private int pageY; + + /** The logical index of the row that was most recently modified. */ + private int logicalRow = -1; + + public AutoScrollerAndSelector(final int topBound, + final int bottomBound, final int gradientArea, + final boolean selectionPaint) { + this.topBound = topBound; + this.bottomBound = bottomBound; + this.gradientArea = gradientArea; + this.selectionPaint = selectionPaint; } - public void onSelectionMove(final int logicalRowIndex) { - if (!paintingInProgress || logicalRowIndex == currentRow) { - return; + @Override + public void execute(final double timestamp) { + final double timeDiff = timestamp - prevTimestamp; + prevTimestamp = timestamp; + + pixelsToScroll += scrollSpeed * (timeDiff / 1000.0d); + final int intPixelsToScroll = (int) pixelsToScroll; + pixelsToScroll -= intPixelsToScroll; + + if (intPixelsToScroll != 0) { + grid.setScrollTop(grid.getScrollTop() + intPixelsToScroll); } - assert currentRow != -1 : "currentRow was uninitialized."; + @SuppressWarnings("hiding") + int logicalRow = getLogicalRowIndex(Util.getElementFromPoint(pageX, + pageY)); + if (logicalRow != -1 && logicalRow != this.logicalRow) { + this.logicalRow = logicalRow; + setSelected(logicalRow, selectionPaint); + } - currentRow = logicalRowIndex; - setSelected(currentRow, selectionPaint); + reschedule(); } - public void onSelectionEnd() { - currentRow = -1; - paintingInProgress = false; + private void updateScrollSpeed(final int pointerPageY) { + + final double ratio; + if (pointerPageY < topBound) { + final double distance = pointerPageY - topBound; + ratio = Math.max(-1, distance / gradientArea); + } + + else if (pointerPageY > bottomBound) { + final double distance = pointerPageY - bottomBound; + ratio = Math.min(1, distance / gradientArea); + } + + else { + ratio = 0; + } + + scrollSpeed = ratio * SCROLL_TOP_SPEED_PX_SEC; + } + + public void start(int logicalRowIndex) { + running = true; + setSelected(logicalRowIndex, selectionPaint); + logicalRow = logicalRowIndex; + reschedule(); + } + + public void stop() { + running = false; + + if (handle != null) { + handle.cancel(); + handle = null; + } + } + + private void reschedule() { + if (running && gradientArea >= GRADIENT_MIN_THRESHOLD_PX) { + handle = AnimationScheduler.get().requestAnimationFrame(this, + grid.getElement()); + } + } + + @SuppressWarnings("hiding") + public void updatePointerCoords(int pageX, int pageY) { + updateScrollSpeed(pageY); + this.pageX = pageX; + this.pageY = pageY; + } + } + + /** + * This class makes sure that pointer movemenets are registered and + * delegated to the autoscroller so that it can: + *
    + *
  • modify the speed in which we autoscroll. + *
  • "paint" a new row with the selection. + *
+ * Essentially, when a pointer is pressed on the selection column, a native + * preview handler is registered (so that selection gestures can happen + * outside of the selection column). The handler itself makes sure that it's + * detached when the pointer is "lifted". + */ + private class AutoScrollHandler { + private AutoScrollerAndSelector autoScroller; + + /** The registration info for {@link #scrollPreviewHandler} */ + private HandlerRegistration handlerRegistration; + + private final NativePreviewHandler scrollPreviewHandler = new NativePreviewHandler() { + @Override + public void onPreviewNativeEvent(final NativePreviewEvent event) { + if (autoScroller == null) { + stop(); + return; + } + + final NativeEvent nativeEvent = event.getNativeEvent(); + int pageY = 0; + int pageX = 0; + switch (event.getTypeInt()) { + case Event.ONMOUSEMOVE: + case Event.ONTOUCHMOVE: + pageY = Util.getTouchOrMouseClientY(nativeEvent); + pageX = Util.getTouchOrMouseClientX(nativeEvent); + autoScroller.updatePointerCoords(pageX, pageY); + break; + case Event.ONMOUSEUP: + case Event.ONTOUCHEND: + case Event.ONTOUCHCANCEL: + stop(); + break; + } + } + }; + + /** + * The top bound, as calculated from the {@link Event#getClientY() + * client} coordinates. + */ + private int topBound = -1; + + /** + * The bottom bound, as calculated from the {@link Event#getClientY() + * client} coordinates. + */ + private int bottomBound = -1; + + /** The size of the autoscroll acceleration area. */ + private int gradientArea; + + public void start(int logicalRowIndex) { + /* + * bounds are updated whenever the autoscroll cycle starts, to make + * sure that the widget hasn't changed in size, moved around, or + * whatnot. + */ + updateScrollBounds(); + + assert handlerRegistration == null : "handlerRegistration was not null"; + assert autoScroller == null : "autoScroller was not null"; + handlerRegistration = Event + .addNativePreviewHandler(scrollPreviewHandler); + + autoScroller = new AutoScrollerAndSelector(topBound, bottomBound, + gradientArea, !isSelected(logicalRowIndex)); + autoScroller.start(logicalRowIndex); + } + + private void updateScrollBounds() { + final Element root = Element.as(grid.getElement()); + final Element tableWrapper = Element.as(root.getChild(2)); + final TableElement table = TableElement.as(tableWrapper + .getFirstChildElement()); + final Element thead = table.getTHead(); + final Element tfoot = table.getTFoot(); + + /* + * GWT _does_ have an "Element.getAbsoluteTop()" that takes both the + * client top and scroll compensation into account, but they're + * calculated wrong for our purposes, so this does something + * similar, but only suitable for us. + * + * Also, this should be a bit faster, since the scroll compensation + * is calculated only once and used in two places. + */ + + final int topBorder = getClientTop(root) + thead.getOffsetHeight(); + final int bottomBorder = getClientTop(tfoot); + + final int scrollCompensation = getScrollCompensation(); + topBound = scrollCompensation + topBorder + SCROLL_AREA_GRADIENT_PX; + bottomBound = scrollCompensation + bottomBorder + - SCROLL_AREA_GRADIENT_PX; + gradientArea = SCROLL_AREA_GRADIENT_PX; + + // modify bounds if they're too tightly packed + if (bottomBound - topBound < MIN_NO_AUTOSCROLL_AREA_PX) { + int adjustment = MIN_NO_AUTOSCROLL_AREA_PX + - (bottomBound - topBound); + topBound -= adjustment / 2; + bottomBound += adjustment / 2; + gradientArea -= adjustment / 2; + } + } + + /** Get the "top" of an element in relation to "client" coordinates. */ + private int getClientTop(final Element e) { + Element cursor = e; + int top = 0; + while (cursor != null) { + top += cursor.getOffsetTop(); + cursor = cursor.getOffsetParent(); + } + return top; + } + + private int getScrollCompensation() { + Element cursor = grid.getElement(); + int scroll = 0; + while (cursor != null) { + scroll -= cursor.getScrollTop(); + cursor = cursor.getParentElement(); + } + + return scroll; + } + + public void stop() { + if (handlerRegistration != null) { + handlerRegistration.removeHandler(); + handlerRegistration = null; + } + + if (autoScroller != null) { + autoScroller.stop(); + autoScroller = null; + } + + removeNativeHandler(); } } @@ -170,7 +445,7 @@ public class MultiSelectionRenderer extends ComplexRenderer { private final Grid grid; private HandlerRegistration nativePreviewHandlerRegistration; - private final SelectionHandler selectionHandler = new SelectionHandler(); + private final AutoScrollHandler autoScrollHandler = new AutoScrollHandler(); public MultiSelectionRenderer(final Grid grid) { this.grid = grid; @@ -194,33 +469,28 @@ public class MultiSelectionRenderer extends ComplexRenderer { @Override public Collection getConsumedEvents() { final HashSet events = new HashSet(); + + /* + * this column's first interest is only to attach a NativePreventHandler + * that does all the magic. These events are the beginning of that + * cycle. + */ events.add(BrowserEvents.MOUSEDOWN); - events.add(BrowserEvents.MOUSEUP); - events.add(BrowserEvents.MOUSEMOVE); events.add(BrowserEvents.TOUCHSTART); + return events; } @Override public void onBrowserEvent(final Cell cell, final NativeEvent event) { - event.preventDefault(); - event.stopPropagation(); - - if (BrowserEvents.TOUCHSTART.equals(event.getType())) { + if (BrowserEvents.TOUCHSTART.equals(event.getType()) + || BrowserEvents.MOUSEDOWN.equals(event.getType())) { injectNativeHandler(); - selectionHandler.onSelectionStart(cell.getRow()); - return; - } - - final Element target = Element.as(event.getEventTarget()); - final int logicalIndex = getLogicalRowIndex(target); - - if (BrowserEvents.MOUSEDOWN.equals(event.getType())) { - selectionHandler.onSelectionStart(logicalIndex); - } else if (BrowserEvents.MOUSEMOVE.equals(event.getType())) { - selectionHandler.onSelectionMove(logicalIndex); - } else if (BrowserEvents.MOUSEUP.equals(event.getType())) { - selectionHandler.onSelectionEnd(); + int logicalRowIndex = getLogicalRowIndex(Element.as(event + .getEventTarget())); + autoScrollHandler.start(logicalRowIndex); + event.preventDefault(); + event.stopPropagation(); } else { throw new IllegalStateException("received unexpected event: " + event.getType()); diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index 6af229bd28..d7310d4264 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -140,7 +140,7 @@ public class GridBasicFeatures extends AbstractComponentTest { createRowActions(); - addHeightByRowActions(); + addHeightActions(); return grid; } @@ -429,7 +429,7 @@ public class GridBasicFeatures extends AbstractComponentTest { } @SuppressWarnings("boxing") - protected void addHeightByRowActions() { + protected void addHeightActions() { createCategory("Height by Rows", "Size"); createBooleanAction("HeightMode Row", "Size", false, @@ -450,6 +450,22 @@ public class GridBasicFeatures extends AbstractComponentTest { addActionForHeightByRows(i + 1d / 3d); addActionForHeightByRows(i + 2d / 3d); } + + Command sizeCommand = new Command() { + @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) { -- cgit v1.2.3 From 87e64d5af9cc1dc2a8d79be6227661b64b2077b5 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Tue, 1 Jul 2014 16:56:03 +0300 Subject: Adds key-related helper methods to Renderers. (#13334) Change-Id: Ic7b1ece8b88126323acc2e216acdebe636091b98 --- .../vaadin/client/ui/grid/EscalatorUpdater.java | 10 ++- .../com/vaadin/client/ui/grid/GridConnector.java | 15 ++++ .../grid/renderers/AbstractRendererConnector.java | 22 ++++++ .../com/vaadin/data/RpcDataProviderExtension.java | 15 +++- .../ui/components/grid/AbstractRenderer.java | 88 ++++++++++++++++++++++ server/src/com/vaadin/ui/components/grid/Grid.java | 17 +++-- .../grid/renderers/AbstractRenderer.java | 69 ----------------- .../ui/components/grid/renderers/DateRenderer.java | 2 + .../ui/components/grid/renderers/HtmlRenderer.java | 2 + .../components/grid/renderers/NumberRenderer.java | 2 + .../ui/components/grid/renderers/TextRenderer.java | 2 + .../tests/components/grid/CustomRenderer.java | 22 +++++- .../tests/components/grid/CustomRendererTest.java | 20 +++++ .../tests/components/grid/IntArrayRenderer.java | 2 +- .../tests/components/grid/RowAwareRenderer.java | 41 ++++++++++ .../client/grid/RowAwareRendererConnector.java | 78 +++++++++++++++++++ 16 files changed, 322 insertions(+), 85 deletions(-) create mode 100644 server/src/com/vaadin/ui/components/grid/AbstractRenderer.java delete mode 100644 server/src/com/vaadin/ui/components/grid/renderers/AbstractRenderer.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java index bfe0ba8bcc..481ddf707e 100644 --- a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java +++ b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java @@ -23,6 +23,9 @@ package com.vaadin.client.ui.grid; *

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

+ * This has a similar function to {@link Grid Grid's} {@link Renderer Renderers} + * , although they operate on different abstraction levels. * * @since 7.4 * @author Vaadin Ltd @@ -30,6 +33,7 @@ package com.vaadin.client.ui.grid; * @see Escalator#getHeader() * @see Escalator#getBody() * @see Escalator#getFooter() + * @see Renderer */ public interface EscalatorUpdater { @@ -75,8 +79,8 @@ public interface EscalatorUpdater { * Note: If rendering of cells is deferred (e.g. because * asynchronous data retrieval), this method is responsible for explicitly * displaying some placeholder data (empty content is valid). Because the - * cells (and rows) in an escalator are recycled, failing to reset a cell - * will lead to invalid data being displayed in the escalator. + * cells (and rows) in an escalator are recycled, failing to reset a cell's + * presentation will lead to wrong data being displayed in the escalator. *

* For performance reasons, the escalator will never autonomously clear any * data in a cell. @@ -85,7 +89,7 @@ public interface EscalatorUpdater { * Information about the row that is being updated. * Note: You should not store nor reuse this reference. * @param cellsToUpdate - * A collection of cells which need to be updated. Note: + * A collection of cells that need to be updated. Note: * You should neither store nor reuse the reference to the * iterable, nor to the individual cells. */ diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index daf938a784..9873ca3d2f 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -536,4 +536,19 @@ public class GridConnector extends AbstractComponentConnector { var model = this.@com.vaadin.client.ui.grid.GridConnector::selectionModel; model.@com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel::deselectByHandle(*)(handle); }-*/; + + /** + * Gets the row key for a row by index. + * + * @param index + * the index of the row for which to get the key + * @return the key for the row at {@code index} + */ + public String getRowKey(int index) { + final JSONObject row = dataSource.getRow(index); + final Object key = dataSource.getRowKey(row); + assert key instanceof String : "Internal key was not a String but a " + + key.getClass().getSimpleName() + " (" + key + ")"; + return (String) key; + } } diff --git a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java index b57b674292..e7cbd5bcd5 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java @@ -23,6 +23,7 @@ import com.vaadin.client.extensions.AbstractExtensionConnector; import com.vaadin.client.metadata.NoDataException; import com.vaadin.client.metadata.Type; import com.vaadin.client.metadata.TypeData; +import com.vaadin.client.ui.grid.GridConnector; import com.vaadin.client.ui.grid.Renderer; /** @@ -121,4 +122,25 @@ public abstract class AbstractRendererConnector extends protected void extend(ServerConnector target) { // NOOP } + + /** + * Gets the row key for a row index. + *

+ * In case this renderer wants be able to identify a row in such a way that + * the server also understands it, the row key is used for that. Rows are + * identified by unified keys between the client and the server. + * + * @param index + * the row index for which to get the row key + * @return the row key for the row at {@code index} + */ + protected String getRowKey(int index) { + final ServerConnector parent = getParent(); + if (parent instanceof GridConnector) { + return ((GridConnector) parent).getRowKey(index); + } else { + throw new IllegalStateException("Renderers can only be used " + + "with a Grid."); + } + } } diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index fd1ca6b9e8..9768950621 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -185,7 +185,20 @@ public class RpcDataProviderExtension extends AbstractExtension { return keys; } - Object getItemId(String key) throws IllegalStateException { + /** + * Gets the registered item id based on its key. + *

+ * A key is used to identify a particular row on both a server and a + * client. This method can be used to get the item id for the row key + * that the client has sent. + * + * @param key + * the row key for which to retrieve an item id + * @return the item id corresponding to {@code key} + * @throws IllegalStateException + * if the key mapper does not have a record of {@code key} . + */ + public Object getItemId(String key) throws IllegalStateException { Object itemId = itemIdToKey.inverse().get(key); if (itemId != null) { return itemId; diff --git a/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java b/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java new file mode 100644 index 0000000000..2f0a7e7ebb --- /dev/null +++ b/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.grid; + +import com.vaadin.server.AbstractClientConnector; +import com.vaadin.server.AbstractExtension; + +/** + * An abstract base class for server-side Grid renderers. + * {@link com.vaadin.client.ui.grid.Renderer Grid renderers}. This class + * currently extends the AbstractExtension superclass, but this fact should be + * regarded as an implementation detail and subject to change in a future major + * or minor Vaadin revision. + * + * @param + * the type this renderer knows how to present + * + * @since 7.4 + * @author Vaadin Ltd + */ +public abstract class AbstractRenderer extends AbstractExtension implements + Renderer { + + private final Class presentationType; + + protected AbstractRenderer(Class presentationType) { + this.presentationType = presentationType; + } + + /** + * This method is inherited from AbstractExtension but should never be + * called directly with an AbstractRenderer. + */ + @Deprecated + @Override + protected Class getSupportedParentType() { + return Grid.class; + } + + /** + * This method is inherited from AbstractExtension but should never be + * called directly with an AbstractRenderer. + */ + @Deprecated + @Override + protected void extend(AbstractClientConnector target) { + super.extend(target); + } + + @Override + public Class getPresentationType() { + return presentationType; + } + + /** + * Gets the item id for a row key. + *

+ * A key is used to identify a particular row on both a server and a client. + * This method can be used to get the item id for the row key that the + * client has sent. + * + * @param key + * the row key for which to retrieve an item id + * @return the item id corresponding to {@code key} + */ + protected Object getItemId(String key) { + if (getParent() instanceof Grid) { + Grid grid = (Grid) getParent(); + return grid.getKeyMapper().getItemId(key); + } else { + throw new IllegalStateException( + "Renderers can be used only with Grid"); + } + } +} diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index d20e4efe8b..287bd1ddfd 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -215,14 +215,14 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { @Override public void selectionChange(SelectionChangeEvent event) { for (Object removedItemId : event.getRemoved()) { - keyMapper().unpin(removedItemId); + getKeyMapper().unpin(removedItemId); } for (Object addedItemId : event.getAdded()) { - keyMapper().pin(addedItemId); + getKeyMapper().pin(addedItemId); } - List keys = keyMapper().getKeys(getSelectedRows()); + List keys = getKeyMapper().getKeys(getSelectedRows()); boolean markAsDirty = true; @@ -259,7 +259,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { @Override public void selectionChange(List selection) { final HashSet newSelection = new HashSet( - keyMapper().getItemIds(selection)); + getKeyMapper().getItemIds(selection)); final HashSet oldSelection = new HashSet( getSelectedRows()); @@ -1062,10 +1062,13 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { } /** - * A shortcut for - * {@link #datasourceExtension}.{@link com.vaadin.data.RpcDataProviderExtension#getKeyMapper() getKeyMapper()} + * Gets the + * {@link com.vaadin.data.RpcDataProviderExtension.DataProviderKeyMapper + * DataProviderKeyMapper} being used by the data source. + * + * @return the key mapper being used by the data source */ - private DataProviderKeyMapper keyMapper() { + DataProviderKeyMapper getKeyMapper() { return datasourceExtension.getKeyMapper(); } diff --git a/server/src/com/vaadin/ui/components/grid/renderers/AbstractRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/AbstractRenderer.java deleted file mode 100644 index d5631c6b60..0000000000 --- a/server/src/com/vaadin/ui/components/grid/renderers/AbstractRenderer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.ui.components.grid.renderers; - -import com.vaadin.server.AbstractClientConnector; -import com.vaadin.server.AbstractExtension; -import com.vaadin.ui.components.grid.Grid; -import com.vaadin.ui.components.grid.Renderer; - -/** - * An abstract base class for server-side Grid renderers. - * {@link com.vaadin.client.ui.grid.Renderer Grid renderers}. This class - * currently extends the AbstractExtension superclass, but this fact should be - * regarded as an implementation detail and subject to change in a future major - * or minor Vaadin revision. - * - * @param - * the type this renderer knows how to present - * - * @since 7.4 - * @author Vaadin Ltd - */ -public abstract class AbstractRenderer extends AbstractExtension implements - Renderer { - - private final Class presentationType; - - protected AbstractRenderer(Class presentationType) { - this.presentationType = presentationType; - } - - /** - * This method is inherited from AbstractExtension but should never be - * called directly with an AbstractRenderer. - */ - @Deprecated - @Override - protected Class getSupportedParentType() { - return Grid.class; - } - - /** - * This method is inherited from AbstractExtension but should never be - * called directly with an AbstractRenderer. - */ - @Deprecated - @Override - protected void extend(AbstractClientConnector target) { - super.extend(target); - } - - @Override - public Class getPresentationType() { - return presentationType; - } -} diff --git a/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java index 8c062252f2..e7280f76aa 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java @@ -19,6 +19,8 @@ import java.text.DateFormat; import java.util.Date; import java.util.Locale; +import com.vaadin.ui.components.grid.AbstractRenderer; + /** * A renderer for presenting date values. * diff --git a/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java index bf5024159f..9c1fbf51d8 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java @@ -15,6 +15,8 @@ */ package com.vaadin.ui.components.grid.renderers; +import com.vaadin.ui.components.grid.AbstractRenderer; + /** * A renderer for presenting HTML content. * diff --git a/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java index bdfe23c366..d071e592ba 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java @@ -18,6 +18,8 @@ package com.vaadin.ui.components.grid.renderers; import java.text.DecimalFormat; import java.util.Locale; +import com.vaadin.ui.components.grid.AbstractRenderer; + /** * A renderer for presenting number values. * diff --git a/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java index e375d5913b..cdef4e17c8 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java @@ -15,6 +15,8 @@ */ package com.vaadin.ui.components.grid.renderers; +import com.vaadin.ui.components.grid.AbstractRenderer; + /** * A renderer for presenting simple plain-text string values. * diff --git a/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java b/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java index 7e079e69b7..9ac1a03df3 100644 --- a/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java +++ b/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java @@ -22,28 +22,42 @@ import com.vaadin.data.util.IndexedContainer; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.tests.widgetset.TestingWidgetSet; +import com.vaadin.ui.Label; import com.vaadin.ui.components.grid.Grid; @Widgetset(TestingWidgetSet.NAME) public class CustomRenderer extends AbstractTestUI { private static final Object INT_ARRAY_PROPERTY = "int array"; + private static final Object VOID_PROPERTY = "void"; + + static final Object ITEM_ID = "itemId1"; + static final String DEBUG_LABEL_ID = "debuglabel"; + static final String INIT_DEBUG_LABEL_CAPTION = "Debug label placeholder"; @Override protected void setup(VaadinRequest request) { IndexedContainer container = new IndexedContainer(); container.addContainerProperty(INT_ARRAY_PROPERTY, int[].class, new int[] {}); + container.addContainerProperty(VOID_PROPERTY, Void.class, null); + + Item item = container.addItem(ITEM_ID); - Object itemId = new Object(); - Item item = container.addItem(itemId); @SuppressWarnings("unchecked") - Property property = item.getItemProperty(INT_ARRAY_PROPERTY); - property.setValue(new int[] { 1, 1, 2, 3, 5, 8, 13 }); + Property propertyIntArray = item + .getItemProperty(INT_ARRAY_PROPERTY); + propertyIntArray.setValue(new int[] { 1, 1, 2, 3, 5, 8, 13 }); + + Label debugLabel = new Label(INIT_DEBUG_LABEL_CAPTION); + debugLabel.setId(DEBUG_LABEL_ID); Grid grid = new Grid(container); grid.getColumn(INT_ARRAY_PROPERTY).setRenderer(new IntArrayRenderer()); + grid.getColumn(VOID_PROPERTY).setRenderer( + new RowAwareRenderer(debugLabel)); addComponent(grid); + addComponent(debugLabel); } @Override diff --git a/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java b/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java index 1827f66777..571a929c7e 100644 --- a/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java @@ -21,6 +21,7 @@ import java.util.List; import org.junit.Test; +import com.vaadin.testbench.elements.LabelElement; import com.vaadin.tests.annotations.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; @@ -35,8 +36,27 @@ public class CustomRendererTest extends MultiBrowserTest { .getText()); } + @Test + public void testRowAwareRenderer() throws Exception { + openTestURL(); + + GridElement grid = findGrid(); + assertEquals("Click me!", grid.getCell(0, 1).getText()); + assertEquals(CustomRenderer.INIT_DEBUG_LABEL_CAPTION, findDebugLabel() + .getText()); + + grid.getCell(0, 1).click(); + assertEquals("row: 0, key: 0", grid.getCell(0, 1).getText()); + assertEquals("key: 0, itemId: " + CustomRenderer.ITEM_ID, + findDebugLabel().getText()); + } + private GridElement findGrid() { List elements = $(GridElement.class).all(); return elements.get(0); } + + private LabelElement findDebugLabel() { + return $(LabelElement.class).id(CustomRenderer.DEBUG_LABEL_ID); + } } diff --git a/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java b/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java index 9ebae4587d..142c370e13 100644 --- a/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java +++ b/uitest/src/com/vaadin/tests/components/grid/IntArrayRenderer.java @@ -18,7 +18,7 @@ package com.vaadin.tests.components.grid; import org.json.JSONArray; import org.json.JSONException; -import com.vaadin.ui.components.grid.renderers.AbstractRenderer; +import com.vaadin.ui.components.grid.AbstractRenderer; public class IntArrayRenderer extends AbstractRenderer { public IntArrayRenderer() { diff --git a/uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java b/uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java new file mode 100644 index 0000000000..f55f5f064c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/RowAwareRenderer.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid; + +import org.json.JSONObject; + +import com.vaadin.tests.widgetset.client.grid.RowAwareRendererConnector.RowAwareRendererRpc; +import com.vaadin.ui.Label; +import com.vaadin.ui.components.grid.AbstractRenderer; + +public class RowAwareRenderer extends AbstractRenderer { + public RowAwareRenderer(final Label debugLabel) { + super(Void.class); + registerRpc(new RowAwareRendererRpc() { + @Override + public void clicky(String key) { + Object itemId = getItemId(key); + debugLabel.setValue("key: " + key + ", itemId: " + itemId); + } + }); + } + + @Override + public Object encode(Void value) { + return JSONObject.NULL; + } + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java new file mode 100644 index 0000000000..c82c6c9a18 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.client.grid; + +import java.util.Arrays; +import java.util.Collection; + +import com.google.gwt.dom.client.BrowserEvents; +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.user.client.DOM; +import com.vaadin.client.ui.grid.Cell; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Renderer; +import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; +import com.vaadin.client.ui.grid.renderers.ComplexRenderer; +import com.vaadin.shared.communication.ServerRpc; +import com.vaadin.shared.ui.Connect; + +@Connect(com.vaadin.tests.components.grid.RowAwareRenderer.class) +public class RowAwareRendererConnector extends AbstractRendererConnector { + public interface RowAwareRendererRpc extends ServerRpc { + void clicky(String key); + } + + public class RowAwareRenderer extends ComplexRenderer { + + @Override + public Collection getConsumedEvents() { + return Arrays.asList(BrowserEvents.CLICK); + } + + @Override + public void init(FlyweightCell cell) { + DivElement div = DivElement.as(DOM.createDiv()); + div.setAttribute("style", + "border: 1px solid red; background: pink;"); + div.setInnerText("Click me!"); + cell.getElement().appendChild(div); + } + + @Override + public void render(FlyweightCell cell, Void data) { + // NOOP + } + + @Override + public void onBrowserEvent(Cell cell, NativeEvent event) { + int row = cell.getRow(); + String key = getRowKey(row); + getRpcProxy(RowAwareRendererRpc.class).clicky(key); + cell.getElement().setInnerText("row: " + row + ", key: " + key); + } + } + + @Override + protected Class getType() { + return Void.class; + } + + @Override + protected Renderer createRenderer() { + return new RowAwareRenderer(); + } +} -- cgit v1.2.3 From a2db5af7e6978da165748f6b5ab94880a52d5f96 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Fri, 4 Jul 2014 14:37:48 +0300 Subject: Fix setting SelectionMode on application start (#13334) Change-Id: I7993a1e7c0ecfc1f75adfe0c156cd41528fea329 --- client/src/com/vaadin/client/ui/grid/GridConnector.java | 6 ++++-- .../vaadin/tests/components/grid/GridBasicFeatures.java | 4 +++- .../tests/components/grid/GridBasicFeaturesTest.java | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 9873ca3d2f..9ba1e9f038 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -119,8 +119,8 @@ public class GridConnector extends AbstractComponentConnector { // find new deselections for (String key : selectedKeys) { - changed = true; if (!stateKeys.contains(key)) { + changed = true; deselectByHandle(dataSource.getHandleByKey(key)); } } @@ -203,7 +203,7 @@ public class GridConnector extends AbstractComponentConnector { * Maps a generated column id to a grid column instance */ private Map columnIdToColumn = new HashMap(); - private AbstractRowHandleSelectionModel selectionModel = new SelectionModelMulti(); + private AbstractRowHandleSelectionModel selectionModel = createSelectionModel(SharedSelectionMode.NONE); private RpcDataSource dataSource; private final RowKeyHelper rowKeyHelper = new RowKeyHelper(); @@ -495,7 +495,9 @@ public class GridConnector extends AbstractComponentConnector { if (!model.getClass().equals(selectionModel.getClass())) { selectionModel = model; getWidget().setSelectionModel(model); + rowKeyHelper.selectedKeys.clear(); } + } private Logger getLogger() { diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index d7310d4264..995188db5c 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -128,6 +128,8 @@ public class GridBasicFeatures extends AbstractComponentTest { grid.getColumn("Column" + col).setWidth(100 + col * 50); } + grid.setSelectionMode(SelectionMode.NONE); + createGridActions(); createColumnActions(); @@ -165,7 +167,7 @@ public class GridBasicFeatures extends AbstractComponentTest { selectionModes.put("single", SelectionMode.SINGLE); selectionModes.put("multi", SelectionMode.MULTI); selectionModes.put("none", SelectionMode.NONE); - createSelectAction("Selection mode", "State", selectionModes, "multi", + createSelectAction("Selection mode", "State", selectionModes, "none", new Command() { @Override public void execute(Grid grid, SelectionMode selectionMode, diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index 3dc8ac814f..2546def990 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -306,6 +306,8 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { public void testSelectOnOff() throws Exception { openTestURL(); + setSelectionModelMulti(); + assertFalse("row shouldn't start out as selected", isSelected(getRow(0))); toggleFirstRowSelection(); @@ -317,6 +319,9 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { @Test public void testSelectOnScrollOffScroll() throws Exception { openTestURL(); + + setSelectionModelMulti(); + assertFalse("row shouldn't start out as selected", isSelected(getRow(0))); toggleFirstRowSelection(); @@ -332,6 +337,9 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { @Test public void testSelectScrollOnScrollOff() throws Exception { openTestURL(); + + setSelectionModelMulti(); + assertFalse("row shouldn't start out as selected", isSelected(getRow(0))); @@ -349,6 +357,9 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { @Test public void testSelectScrollOnOffScroll() throws Exception { openTestURL(); + + setSelectionModelMulti(); + assertFalse("row shouldn't start out as selected", isSelected(getRow(0))); @@ -395,6 +406,10 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { assertTrue(vscrollStyleName.contains(stylename + "-scroller-vertical")); } + private void setSelectionModelMulti() { + selectMenuPath("Component", "State", "Selection mode", "multi"); + } + private WebElement getBodyCellByRowAndColumn(int row, int column) { return getGridElement().getCell(row, column); } -- cgit v1.2.3 From d19d9dc0fdc0fd45da340c3301e0cd08048c7959 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Fri, 4 Jul 2014 16:34:18 +0300 Subject: Fix GridClientColumnRenderers test (#13334) Change-Id: Icca020d2a0478ac385932d3ff1aedd5df9c530b4 --- .../src/com/vaadin/tests/components/grid/GridClientRenderers.java | 6 +----- .../widgetset/client/grid/GridClientColumnRendererConnector.java | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index 0cb5dea8f8..9527feb341 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -35,7 +35,7 @@ import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers; /** * Tests Grid client side renderers - * + * * @since 7.4 * @author Vaadin Ltd */ @@ -221,10 +221,6 @@ public class GridClientRenderers extends MultiBrowserTest { for (int i = 1, l = 70; i < l; ++i) { - if (i == 19) { - System.err.println("foo"); - } - String str_a = gridElem.getCell(i - 1, 0).getAttribute("innerHTML"); String str_b = gridElem.getCell(i, 0).getAttribute("innerHTML"); diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index 48aba1d2dd..549d6eee85 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -117,6 +117,7 @@ public class GridClientColumnRendererConnector extends @Override protected void init() { Grid grid = getWidget(); + grid.setSelectionMode(Grid.SelectionMode.NONE); // Generated some column data List columnData = new ArrayList(); -- cgit v1.2.3 From 20e2a3b5eefa03b2d4db8af15e30d1958bc7047f Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 7 Jul 2014 12:07:43 +0300 Subject: Fix GridSingleColumnTest & CustomRendererTest Change-Id: Ifa789542441e2560a57afe372c6b94d5d9e6b7e6 --- uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java | 2 ++ uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java | 2 ++ 2 files changed, 4 insertions(+) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java b/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java index 9ac1a03df3..d217829bcb 100644 --- a/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java +++ b/uitest/src/com/vaadin/tests/components/grid/CustomRenderer.java @@ -24,6 +24,7 @@ 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 { @@ -56,6 +57,7 @@ public class CustomRenderer extends AbstractTestUI { grid.getColumn(INT_ARRAY_PROPERTY).setRenderer(new IntArrayRenderer()); grid.getColumn(VOID_PROPERTY).setRenderer( new RowAwareRenderer(debugLabel)); + grid.setSelectionMode(SelectionMode.NONE); addComponent(grid); addComponent(debugLabel); } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java index 56fe904093..75b83ea3aa 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumn.java @@ -20,6 +20,7 @@ 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 { @@ -36,6 +37,7 @@ public class GridSingleColumn extends AbstractTestUI { } Grid grid = new Grid(indexedContainer); + grid.setSelectionMode(SelectionMode.NONE); GridColumn column = grid.getColumn("column1"); -- cgit v1.2.3 From ec205707eacb1187ab8f21e7e7c5150944ef349b Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 7 Jul 2014 15:48:00 +0300 Subject: Increase simulated latency in GridClientRenderers test Change-Id: I53bc77a1ba36eadee7c1c08f8eaffcece00e81fc --- .../tests/components/grid/GridClientRenderers.java | 55 +++++++++++----------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index 9527feb341..bea941d6a3 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -41,16 +41,9 @@ import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers; */ public class GridClientRenderers extends MultiBrowserTest { + private static final double SLEEP_MULTIPLIER = 1.2; private int latency = 0; - @Override - protected DesiredCapabilities getDesiredCapabilities() { - DesiredCapabilities c = new DesiredCapabilities( - super.getDesiredCapabilities()); - c.setCapability("handlesAlerts", true); - return c; - } - @Override protected Class getUIClass() { return GridClientColumnRenderers.class; @@ -58,10 +51,11 @@ public class GridClientRenderers extends MultiBrowserTest { @Override protected String getDeploymentPath() { + String path = super.getDeploymentPath(); if (latency > 0) { - return super.getDeploymentPath() + "?latency=" + latency; + path += (path.contains("?") ? "&" : "?") + "latency=" + latency; } - return super.getDeploymentPath(); + return path; } @ServerClass("com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers.GridController") @@ -89,8 +83,8 @@ public class GridClientRenderers extends MultiBrowserTest { gwtButton.click(); // Should be an alert visible - assertEquals("Button did not contain text \"Clicked\"", - gwtButton.getText(), "Clicked"); + assertEquals("Button did not contain text \"Clicked\"", "Clicked", + gwtButton.getText()); } @Test @@ -118,21 +112,23 @@ public class GridClientRenderers extends MultiBrowserTest { @Test public void rowsWithDataHasStyleName() throws Exception { - // Simulate network latency with 4000ms - latency = 4000; + // Simulate network latency with 2000ms + latency = 2000; openTestURL(); - TestBenchElement row = getGrid().getRow(1); + 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(latency + 1000); + sleep((int) (latency * SLEEP_MULTIPLIER)); - row = getGrid().getRow(1); + 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")); @@ -141,13 +137,20 @@ public class GridClientRenderers extends MultiBrowserTest { @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(getDesiredCapabilities())) { + if (BrowserUtil.isChrome(desiredCapabilities)) { colorRed = "rgb(255, 0, 0)"; colorWhite = "rgb(255, 255, 255)"; } @@ -156,17 +159,19 @@ public class GridClientRenderers extends MultiBrowserTest { addColumn(Renderers.CPLX_RENDERER); + sleep((int) (latency * SLEEP_MULTIPLIER)); + + getGrid().scrollToRow(60); // Cell should be red (setContentVisible set cell red) - String backgroundColor = getGrid().getCell(51, 1).getCssValue( - "backgroundColor"); + TestBenchElement cell = getGrid().getCell(51, 1); + String backgroundColor = cell.getCssValue("backgroundColor"); assertEquals("Background color was not red.", colorRed, backgroundColor); // Wait for data to arrive - sleep(latency + 1000); + sleep((int) (latency * SLEEP_MULTIPLIER)); // Cell should no longer be red - backgroundColor = getGrid().getCell(51, 1).getCssValue( - "backgroundColor"); + backgroundColor = cell.getCssValue("backgroundColor"); assertEquals("Background color was not white", colorWhite, backgroundColor); } @@ -177,7 +182,6 @@ public class GridClientRenderers extends MultiBrowserTest { $(NativeButtonElement.class).caption("Trigger sorting event").first() .click(); - sleep(1000); String consoleText = $(LabelElement.class).id("testDebugConsole") .getText(); @@ -190,10 +194,8 @@ public class GridClientRenderers extends MultiBrowserTest { @Test public void testListSorter() throws Exception { openTestURL(); - sleep(1000); $(NativeButtonElement.class).caption("Shuffle").first().click(); - sleep(1000); GridElement gridElem = $(MyClientGridElement.class).first(); @@ -217,7 +219,6 @@ public class GridClientRenderers extends MultiBrowserTest { assertTrue("Grid shuffled", shuffled); $(NativeButtonElement.class).caption("Test sorting").first().click(); - sleep(1000); for (int i = 1, l = 70; i < l; ++i) { -- cgit v1.2.3 From 07ef5c9d52c7e30ca5197fe43dbf301178c81a9d Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Tue, 8 Jul 2014 12:04:56 +0300 Subject: Removes the version number from @since in Grid classes (#13334) Change-Id: I36192c46b359b8307c5bb1faf71c3b9a20e77fb8 --- client/src/com/vaadin/client/data/AbstractRemoteDataSource.java | 2 +- client/src/com/vaadin/client/data/CacheStrategy.java | 2 +- client/src/com/vaadin/client/data/DataChangeHandler.java | 2 +- client/src/com/vaadin/client/data/DataSource.java | 2 +- client/src/com/vaadin/client/data/RpcDataSourceConnector.java | 2 +- client/src/com/vaadin/client/ui/grid/Cell.java | 1 + client/src/com/vaadin/client/ui/grid/ColumnConfiguration.java | 2 +- client/src/com/vaadin/client/ui/grid/ColumnGroup.java | 2 +- client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java | 2 +- client/src/com/vaadin/client/ui/grid/Escalator.java | 2 +- client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java | 2 +- client/src/com/vaadin/client/ui/grid/FlyweightCell.java | 2 +- client/src/com/vaadin/client/ui/grid/FlyweightRow.java | 2 +- client/src/com/vaadin/client/ui/grid/Grid.java | 2 +- client/src/com/vaadin/client/ui/grid/GridColumn.java | 2 +- client/src/com/vaadin/client/ui/grid/GridConnector.java | 2 +- client/src/com/vaadin/client/ui/grid/PositionFunction.java | 2 +- client/src/com/vaadin/client/ui/grid/Renderer.java | 2 +- client/src/com/vaadin/client/ui/grid/Row.java | 2 +- client/src/com/vaadin/client/ui/grid/RowContainer.java | 2 +- client/src/com/vaadin/client/ui/grid/RowVisibilityChangeEvent.java | 2 +- client/src/com/vaadin/client/ui/grid/RowVisibilityChangeHandler.java | 2 +- client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java | 2 +- client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java | 2 +- client/src/com/vaadin/client/ui/grid/datasources/ListSorter.java | 2 +- .../vaadin/client/ui/grid/renderers/AbstractRendererConnector.java | 2 +- client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java | 2 +- client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java | 2 +- .../com/vaadin/client/ui/grid/renderers/DateRendererConnector.java | 2 +- client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java | 2 +- client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java | 2 +- .../com/vaadin/client/ui/grid/renderers/NumberRendererConnector.java | 2 +- client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java | 2 +- .../com/vaadin/client/ui/grid/renderers/TextRendererConnector.java | 2 +- .../vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java | 2 +- client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java | 2 +- .../vaadin/client/ui/grid/selection/HasSelectionChangeHandlers.java | 2 +- .../com/vaadin/client/ui/grid/selection/SelectionChangeEvent.java | 2 +- .../com/vaadin/client/ui/grid/selection/SelectionChangeHandler.java | 2 +- client/src/com/vaadin/client/ui/grid/selection/SelectionModel.java | 2 +- .../src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java | 2 +- .../src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java | 2 +- .../com/vaadin/client/ui/grid/selection/SelectionModelSingle.java | 2 +- client/src/com/vaadin/client/ui/grid/sort/Sort.java | 2 +- client/src/com/vaadin/client/ui/grid/sort/SortEvent.java | 2 +- client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java | 2 +- client/src/com/vaadin/client/ui/grid/sort/SortOrder.java | 2 +- client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java | 5 ----- server/src/com/vaadin/data/RpcDataProviderExtension.java | 2 +- server/src/com/vaadin/ui/components/grid/AbstractRenderer.java | 2 +- server/src/com/vaadin/ui/components/grid/ColumnGroup.java | 2 +- server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java | 2 +- server/src/com/vaadin/ui/components/grid/Grid.java | 2 +- server/src/com/vaadin/ui/components/grid/GridColumn.java | 2 +- server/src/com/vaadin/ui/components/grid/Renderer.java | 2 +- server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java | 2 +- server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java | 2 +- .../src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java | 2 +- server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java | 2 +- .../vaadin/ui/components/grid/selection/AbstractSelectionModel.java | 2 +- .../com/vaadin/ui/components/grid/selection/MultiSelectionModel.java | 2 +- .../com/vaadin/ui/components/grid/selection/NoSelectionModel.java | 2 +- .../vaadin/ui/components/grid/selection/SelectionChangeEvent.java | 2 +- .../vaadin/ui/components/grid/selection/SelectionChangeListener.java | 2 +- .../vaadin/ui/components/grid/selection/SelectionChangeNotifier.java | 2 +- .../src/com/vaadin/ui/components/grid/selection/SelectionModel.java | 2 +- .../vaadin/ui/components/grid/selection/SingleSelectionModel.java | 2 +- shared/src/com/vaadin/shared/data/DataProviderRpc.java | 2 +- shared/src/com/vaadin/shared/data/DataProviderState.java | 2 +- shared/src/com/vaadin/shared/data/DataRequestRpc.java | 2 +- shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java | 2 +- shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java | 2 +- shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java | 2 +- shared/src/com/vaadin/shared/ui/grid/GridColumnState.java | 2 +- shared/src/com/vaadin/shared/ui/grid/GridConstants.java | 2 +- shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java | 2 +- shared/src/com/vaadin/shared/ui/grid/GridState.java | 2 +- shared/src/com/vaadin/shared/ui/grid/HeightMode.java | 2 +- shared/src/com/vaadin/shared/ui/grid/Range.java | 2 +- shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java | 2 +- shared/src/com/vaadin/shared/ui/grid/SortDirection.java | 2 +- uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java | 2 +- uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java | 2 +- uitest/src/com/vaadin/tests/components/grid/GridElement.java | 2 +- .../com/vaadin/tests/widgetset/client/grid/TestGridConnector.java | 2 +- uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java | 2 +- uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java | 2 +- 87 files changed, 86 insertions(+), 90 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java index d6a609a3c8..bec6e330bc 100644 --- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java +++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java @@ -35,7 +35,7 @@ import com.vaadin.shared.ui.grid.Range; * {@link #setRowData(int, List)}. {@link #setEstimatedSize(int)} should be used * based on estimations of how many rows are available. * - * @since 7.4 + * @since * @author Vaadin Ltd * @param * the row type diff --git a/client/src/com/vaadin/client/data/CacheStrategy.java b/client/src/com/vaadin/client/data/CacheStrategy.java index 79ce537314..3448659e61 100644 --- a/client/src/com/vaadin/client/data/CacheStrategy.java +++ b/client/src/com/vaadin/client/data/CacheStrategy.java @@ -22,7 +22,7 @@ import com.vaadin.shared.ui.grid.Range; * Determines what data an {@link AbstractRemoteDataSource} should fetch and * keep cached. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface CacheStrategy { diff --git a/client/src/com/vaadin/client/data/DataChangeHandler.java b/client/src/com/vaadin/client/data/DataChangeHandler.java index 52065ee4d7..9553ef53c1 100644 --- a/client/src/com/vaadin/client/data/DataChangeHandler.java +++ b/client/src/com/vaadin/client/data/DataChangeHandler.java @@ -20,7 +20,7 @@ package com.vaadin.client.data; * Callback interface used by {@link DataSource} to inform its user about * updates to the data. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface DataChangeHandler { diff --git a/client/src/com/vaadin/client/data/DataSource.java b/client/src/com/vaadin/client/data/DataSource.java index 695a2a7c2f..33f60eadcc 100644 --- a/client/src/com/vaadin/client/data/DataSource.java +++ b/client/src/com/vaadin/client/data/DataSource.java @@ -21,7 +21,7 @@ package com.vaadin.client.data; * items (e.g. rows) of a specified type. The data source is a lazy view into a * larger data set. * - * @since 7.4 + * @since * @author Vaadin Ltd * @param * the row type diff --git a/client/src/com/vaadin/client/data/RpcDataSourceConnector.java b/client/src/com/vaadin/client/data/RpcDataSourceConnector.java index 3761ea92df..0bee9dc34d 100644 --- a/client/src/com/vaadin/client/data/RpcDataSourceConnector.java +++ b/client/src/com/vaadin/client/data/RpcDataSourceConnector.java @@ -39,7 +39,7 @@ import com.vaadin.shared.ui.grid.Range; * connector type. This will be changed once framework support for something * more flexible has been implemented. * - * @since 7.4 + * @since * @author Vaadin Ltd */ @Connect(com.vaadin.data.RpcDataProviderExtension.class) diff --git a/client/src/com/vaadin/client/ui/grid/Cell.java b/client/src/com/vaadin/client/ui/grid/Cell.java index 33495ebf87..45a7eef554 100644 --- a/client/src/com/vaadin/client/ui/grid/Cell.java +++ b/client/src/com/vaadin/client/ui/grid/Cell.java @@ -24,6 +24,7 @@ import com.google.gwt.dom.client.Element; * class is still under debate and the API is not final. Improve the description * when API has been finalized. * + * @since * @author Vaadin Ltd */ public class Cell { diff --git a/client/src/com/vaadin/client/ui/grid/ColumnConfiguration.java b/client/src/com/vaadin/client/ui/grid/ColumnConfiguration.java index c8d9a750bc..e69b5e7a48 100644 --- a/client/src/com/vaadin/client/ui/grid/ColumnConfiguration.java +++ b/client/src/com/vaadin/client/ui/grid/ColumnConfiguration.java @@ -19,7 +19,7 @@ package com.vaadin.client.ui.grid; /** * A representation of the columns in an instance of {@link Escalator}. * - * @since 7.4 + * @since * @author Vaadin Ltd * @see Escalator#getColumnConfiguration() */ diff --git a/client/src/com/vaadin/client/ui/grid/ColumnGroup.java b/client/src/com/vaadin/client/ui/grid/ColumnGroup.java index c425d1b07c..c58f90f10b 100644 --- a/client/src/com/vaadin/client/ui/grid/ColumnGroup.java +++ b/client/src/com/vaadin/client/ui/grid/ColumnGroup.java @@ -31,7 +31,7 @@ import com.vaadin.client.ui.grid.renderers.TextRenderer; * @param * The row type of the grid. The row type is the POJO type from where * the data is retrieved into the column cells. - * @since 7.4 + * @since * @author Vaadin Ltd */ public class ColumnGroup { diff --git a/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java b/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java index 10290a0639..90e7c1f887 100644 --- a/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java +++ b/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java @@ -30,7 +30,7 @@ import java.util.Set; * * @param * Row type - * @since 7.4 + * @since * @author Vaadin Ltd */ public class ColumnGroupRow { diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index c8feb6d18e..271e2509b7 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -230,7 +230,7 @@ abstract class JsniWorkaround { * A low-level table-like widget that features a scrolling virtual viewport and * lazily generated rows. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class Escalator extends Widget { diff --git a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java index 481ddf707e..aae6b63d20 100644 --- a/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java +++ b/client/src/com/vaadin/client/ui/grid/EscalatorUpdater.java @@ -27,7 +27,7 @@ package com.vaadin.client.ui.grid; * This has a similar function to {@link Grid Grid's} {@link Renderer Renderers} * , although they operate on different abstraction levels. * - * @since 7.4 + * @since * @author Vaadin Ltd * @see RowContainer#setEscalatorUpdater(EscalatorUpdater) * @see Escalator#getHeader() diff --git a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java index 3364f71bd1..17301214c8 100644 --- a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java +++ b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java @@ -32,7 +32,7 @@ import com.vaadin.client.ui.grid.FlyweightRow.CellIterator; * and so should not be stored anywhere outside of the method providing these * instances. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class FlyweightCell { diff --git a/client/src/com/vaadin/client/ui/grid/FlyweightRow.java b/client/src/com/vaadin/client/ui/grid/FlyweightRow.java index f89e2eed52..a5447715e5 100644 --- a/client/src/com/vaadin/client/ui/grid/FlyweightRow.java +++ b/client/src/com/vaadin/client/ui/grid/FlyweightRow.java @@ -29,7 +29,7 @@ import com.google.gwt.dom.client.Node; * There is only one instance per Escalator. This is designed to be re-used when * rendering rows. * - * @since 7.4 + * @since * @author Vaadin Ltd * @see Escalator.AbstractRowContainer#refreshRow(Node, int) */ diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 4bd07f1909..d1541ba505 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -94,7 +94,7 @@ import com.vaadin.shared.util.SharedUtil; * @param * The row type of the grid. The row type is the POJO type from where * the data is retrieved into the column cells. - * @since 7.4 + * @since * @author Vaadin Ltd */ public class Grid extends Composite implements diff --git a/client/src/com/vaadin/client/ui/grid/GridColumn.java b/client/src/com/vaadin/client/ui/grid/GridColumn.java index 47acd42be9..69be2d5532 100644 --- a/client/src/com/vaadin/client/ui/grid/GridColumn.java +++ b/client/src/com/vaadin/client/ui/grid/GridColumn.java @@ -24,7 +24,7 @@ package com.vaadin.client.ui.grid; * @param * The row type * - * @since 7.4 + * @since * @author Vaadin Ltd */ public abstract class GridColumn extends Grid.AbstractGridColumn { diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 9ba1e9f038..dd27f7f747 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -60,7 +60,7 @@ import com.vaadin.shared.ui.grid.ScrollDestination; * at {@link com.vaadin.shared.data.DataProviderRpc#setRowData(int, List) * DataProviderRpc.setRowData(int, List)}. * - * @since 7.4 + * @since * @author Vaadin Ltd */ @Connect(com.vaadin.ui.components.grid.Grid.class) diff --git a/client/src/com/vaadin/client/ui/grid/PositionFunction.java b/client/src/com/vaadin/client/ui/grid/PositionFunction.java index 65197126b2..4db5efd0fc 100644 --- a/client/src/com/vaadin/client/ui/grid/PositionFunction.java +++ b/client/src/com/vaadin/client/ui/grid/PositionFunction.java @@ -22,7 +22,7 @@ import com.google.gwt.dom.client.Style.Unit; /** * A functional interface that can be used for positioning elements in the DOM. * - * @since 7.4 + * @since * @author Vaadin Ltd */ interface PositionFunction { diff --git a/client/src/com/vaadin/client/ui/grid/Renderer.java b/client/src/com/vaadin/client/ui/grid/Renderer.java index e312a9da20..787a145326 100644 --- a/client/src/com/vaadin/client/ui/grid/Renderer.java +++ b/client/src/com/vaadin/client/ui/grid/Renderer.java @@ -26,7 +26,7 @@ package com.vaadin.client.ui.grid; * @param * The column type * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface Renderer { diff --git a/client/src/com/vaadin/client/ui/grid/Row.java b/client/src/com/vaadin/client/ui/grid/Row.java index a7cbeadd90..2a176f7e82 100644 --- a/client/src/com/vaadin/client/ui/grid/Row.java +++ b/client/src/com/vaadin/client/ui/grid/Row.java @@ -21,7 +21,7 @@ import com.google.gwt.dom.client.Element; /** * A representation of a row in an {@link Escalator}. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface Row { diff --git a/client/src/com/vaadin/client/ui/grid/RowContainer.java b/client/src/com/vaadin/client/ui/grid/RowContainer.java index b0b580d665..d0fb0db103 100644 --- a/client/src/com/vaadin/client/ui/grid/RowContainer.java +++ b/client/src/com/vaadin/client/ui/grid/RowContainer.java @@ -22,7 +22,7 @@ import com.google.gwt.dom.client.Element; * A representation of the rows in each of the sections (header, body and * footer) in an {@link Escalator}. * - * @since 7.4 + * @since * @author Vaadin Ltd * @see Escalator#getHeader() * @see Escalator#getBody() diff --git a/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeEvent.java b/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeEvent.java index 8a3dc6ace8..c5c5e45ca8 100644 --- a/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeEvent.java +++ b/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeEvent.java @@ -21,7 +21,7 @@ import com.google.gwt.event.shared.GwtEvent; /** * Event fired when the range of visible rows changes e.g. because of scrolling. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class RowVisibilityChangeEvent extends diff --git a/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeHandler.java b/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeHandler.java index 7e71fb5bdd..6aa165fe04 100644 --- a/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeHandler.java +++ b/client/src/com/vaadin/client/ui/grid/RowVisibilityChangeHandler.java @@ -22,7 +22,7 @@ import com.google.gwt.event.shared.EventHandler; * Event handler that gets notified when the range of visible rows changes e.g. * because of scrolling. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface RowVisibilityChangeHandler extends EventHandler { diff --git a/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java b/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java index efd64fff84..60b6fa27a3 100644 --- a/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java +++ b/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java @@ -29,7 +29,7 @@ import com.google.gwt.user.client.DOM; * An element-like bundle representing a configurable and visual scrollbar in * one axis. * - * @since 7.4 + * @since * @author Vaadin Ltd * @see VerticalScrollbarBundle * @see HorizontalScrollbarBundle diff --git a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java index 97b358a299..fc76955410 100644 --- a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java +++ b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java @@ -49,7 +49,7 @@ import com.vaadin.shared.util.SharedUtil; * ds.asList().addAll(Arrays.asList(5, 6, 7)); * * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class ListDataSource implements DataSource { diff --git a/client/src/com/vaadin/client/ui/grid/datasources/ListSorter.java b/client/src/com/vaadin/client/ui/grid/datasources/ListSorter.java index 81ea3efd92..9e643825e9 100644 --- a/client/src/com/vaadin/client/ui/grid/datasources/ListSorter.java +++ b/client/src/com/vaadin/client/ui/grid/datasources/ListSorter.java @@ -33,7 +33,7 @@ import com.vaadin.shared.ui.grid.SortDirection; * Provides sorting facility from Grid for the {@link ListDataSource} in-memory * data source. * - * @since 7.4 + * @since * @author Vaadin Ltd * @param * Grid row data type diff --git a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java index e7cbd5bcd5..8a8712372f 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java @@ -36,7 +36,7 @@ import com.vaadin.client.ui.grid.Renderer; * {@link com.vaadin.shared.communication.SharedState SharedState} and no RPC * interfaces. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public abstract class AbstractRendererConnector extends diff --git a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java index 289f3809be..6a1f1c3041 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java @@ -35,7 +35,7 @@ import com.vaadin.client.ui.grid.Renderer; * Also provides a helper method for hiding the cell contents by overriding * {@link #setContentVisible(FlyweightCell, boolean)} * - * @since 7.4 + * @since * @author Vaadin Ltd */ public abstract class ComplexRenderer implements Renderer { diff --git a/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java index 9d18ae9256..fc7d3ac833 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/DateRenderer.java @@ -26,7 +26,7 @@ import com.vaadin.client.ui.grid.Renderer; /** * A renderer for rendering dates into cells * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class DateRenderer implements Renderer { diff --git a/client/src/com/vaadin/client/ui/grid/renderers/DateRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/DateRendererConnector.java index 71c7ff78e3..52ae7d9b6b 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/DateRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/DateRendererConnector.java @@ -25,7 +25,7 @@ import com.vaadin.shared.ui.Connect; * string, and displayed as-is on the client side. This is to be able to support * the server's locale. * - * @since 7.4 + * @since * @author Vaadin Ltd */ @Connect(com.vaadin.ui.components.grid.renderers.DateRenderer.class) diff --git a/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java index 6cb9603d3c..36c5d2bb0f 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/HtmlRenderer.java @@ -28,7 +28,7 @@ import com.vaadin.client.ui.grid.Renderer; * contract. For more information see * {@link SafeHtmlUtils#fromSafeConstant(String)}. * - * @since 7.4 + * @since * @author Vaadin Ltd * @see SafeHtmlUtils#fromSafeConstant(String) */ diff --git a/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java index b1bf7083a5..aa23bc2370 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/NumberRenderer.java @@ -24,7 +24,7 @@ import com.vaadin.client.ui.grid.Renderer; * default uses the default number format returned by * {@link NumberFormat#getDecimalFormat()}. * - * @since 7.4 + * @since * @author Vaadin Ltd * @param * The number type to render. diff --git a/client/src/com/vaadin/client/ui/grid/renderers/NumberRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/NumberRendererConnector.java index c698144d30..cba29d0690 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/NumberRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/NumberRendererConnector.java @@ -26,7 +26,7 @@ import com.vaadin.shared.ui.Connect; * string, and displayed as-is on the client side. This is to be able to support * the server's locale. * - * @since 7.4 + * @since * @author Vaadin Ltd */ @Connect(com.vaadin.ui.components.grid.renderers.NumberRenderer.class) diff --git a/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java index 36ffbae22d..d2f3520c43 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/TextRenderer.java @@ -21,7 +21,7 @@ import com.vaadin.client.ui.grid.Renderer; /** * Renderer that renders text into a cell. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class TextRenderer implements Renderer { diff --git a/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java index 76fce7b4b6..18cc84cd34 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java @@ -20,7 +20,7 @@ import com.vaadin.shared.ui.Connect; /** * A connector for {@link TextRenderer}. * - * @since 7.4 + * @since * @author Vaadin Ltd */ @Connect(com.vaadin.ui.components.grid.renderers.TextRenderer.class) diff --git a/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java index c0dcf0505d..1816ac974a 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java @@ -22,7 +22,7 @@ import com.vaadin.shared.ui.Connect; /** * A connector for {@link UnsafeHtmlRenderer} * - * @since 7.4 + * @since * @author Vaadin Ltd */ @Connect(com.vaadin.ui.components.grid.renderers.HtmlRenderer.class) diff --git a/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java index 0937e8c1f2..b7cd72600a 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/WidgetRenderer.java @@ -22,7 +22,7 @@ import com.vaadin.client.ui.grid.FlyweightCell; /** * A renderer for rendering widgets into cells. * - * @since 7.4 + * @since * @author Vaadin Ltd * @param * the row data type diff --git a/client/src/com/vaadin/client/ui/grid/selection/HasSelectionChangeHandlers.java b/client/src/com/vaadin/client/ui/grid/selection/HasSelectionChangeHandlers.java index c531265590..342c426b55 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/HasSelectionChangeHandlers.java +++ b/client/src/com/vaadin/client/ui/grid/selection/HasSelectionChangeHandlers.java @@ -21,7 +21,7 @@ import com.google.gwt.event.shared.HandlerRegistration; * Marker interface for widgets that fires selection change events. * * @author Vaadin Ltd - * @since 7.4 + * @since */ public interface HasSelectionChangeHandlers { diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeEvent.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeEvent.java index 86d9c97c36..5c5afef065 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeEvent.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeEvent.java @@ -26,7 +26,7 @@ import com.vaadin.client.ui.grid.Grid; /** * Event object describing a change in Grid row selection state. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class SelectionChangeEvent extends GwtEvent { diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeHandler.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeHandler.java index aa61bdecdf..a469f5af1f 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeHandler.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionChangeHandler.java @@ -20,7 +20,7 @@ import com.google.gwt.event.shared.EventHandler; /** * Handler for {@link SelectionChangeEvent}s. * - * @since 7.4 + * @since * @author Vaadin Ltd * @param * The row data type diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModel.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModel.java index 989a8946c7..cc2f2b06d9 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModel.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModel.java @@ -27,7 +27,7 @@ import com.vaadin.client.ui.grid.Renderer; * dispatching events when the selection state changes. * * @author Vaadin Ltd - * @since 7.4 + * @since * @param * Grid's row type */ diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java index 6ebd7f4044..6f2896b43a 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelMulti.java @@ -28,7 +28,7 @@ import com.vaadin.client.ui.grid.Renderer; * Multi-row selection model. * * @author Vaadin Ltd - * @since 7.4 + * @since */ public class SelectionModelMulti extends AbstractRowHandleSelectionModel implements SelectionModel.Multi { diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java index 59bf248032..8192237da0 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelNone.java @@ -26,7 +26,7 @@ import com.vaadin.client.ui.grid.Renderer; * No-row selection model. * * @author Vaadin Ltd - * @since 7.4 + * @since */ public class SelectionModelNone extends AbstractRowHandleSelectionModel implements SelectionModel.None { diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java index 4ef792f1c7..2647ae9c56 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java @@ -26,7 +26,7 @@ import com.vaadin.client.ui.grid.Renderer; * Single-row selection model. * * @author Vaadin Ltd - * @since 7.4 + * @since */ public class SelectionModelSingle extends AbstractRowHandleSelectionModel implements SelectionModel.Single { diff --git a/client/src/com/vaadin/client/ui/grid/sort/Sort.java b/client/src/com/vaadin/client/ui/grid/sort/Sort.java index 64fec445ae..00658c4375 100644 --- a/client/src/com/vaadin/client/ui/grid/sort/Sort.java +++ b/client/src/com/vaadin/client/ui/grid/sort/Sort.java @@ -24,7 +24,7 @@ import com.vaadin.shared.ui.grid.SortDirection; /** * Fluid Sort descriptor object. * - * @since 7.4 + * @since * @author Vaadin Ltd * @param T * grid data type diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java b/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java index d39cdfc4f2..baa12ae224 100644 --- a/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java +++ b/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java @@ -25,7 +25,7 @@ import com.vaadin.client.ui.grid.Grid; * A sort event, fired by the Grid when it needs its data source to provide data * sorted in a specific manner. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class SortEvent extends GwtEvent> { diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java b/client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java index 8895b43631..57e7fc2ead 100644 --- a/client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java +++ b/client/src/com/vaadin/client/ui/grid/sort/SortEventHandler.java @@ -21,7 +21,7 @@ import com.google.gwt.event.shared.EventHandler; * Handler for a Grid sort event, called when the Grid needs its data source to * provide data sorted in a specific manner. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface SortEventHandler extends EventHandler { diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java index 09b1a48afa..34279bdc04 100644 --- a/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java +++ b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java @@ -21,7 +21,7 @@ import com.vaadin.shared.ui.grid.SortDirection; /** * Sort order descriptor. Contains column and direction references. * - * @since 7.4 + * @since * @author Vaadin Ltd * @param T * grid data type diff --git a/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java b/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java index 823eb224ea..55a2b56ee2 100644 --- a/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java +++ b/client/tests/src/com/vaadin/client/ui/grid/ListDataSourceTest.java @@ -27,11 +27,6 @@ import org.junit.Test; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.ui.grid.datasources.ListDataSource; -/** - * - * @since 7.2 - * @author Vaadin Ltd - */ public class ListDataSourceTest { @Test diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index 9768950621..e6b5050d90 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -61,7 +61,7 @@ import com.vaadin.ui.components.grid.Renderer; * This will be changed once framework support for something more flexible has * been implemented. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class RpcDataProviderExtension extends AbstractExtension { diff --git a/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java b/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java index 2f0a7e7ebb..d1cf77c24b 100644 --- a/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/AbstractRenderer.java @@ -28,7 +28,7 @@ import com.vaadin.server.AbstractExtension; * @param * the type this renderer knows how to present * - * @since 7.4 + * @since * @author Vaadin Ltd */ public abstract class AbstractRenderer extends AbstractExtension implements diff --git a/server/src/com/vaadin/ui/components/grid/ColumnGroup.java b/server/src/com/vaadin/ui/components/grid/ColumnGroup.java index 92cfd946a8..ec676dfb87 100644 --- a/server/src/com/vaadin/ui/components/grid/ColumnGroup.java +++ b/server/src/com/vaadin/ui/components/grid/ColumnGroup.java @@ -27,7 +27,7 @@ import com.vaadin.shared.ui.grid.ColumnGroupState; * Column groups are used to group columns together for adding common auxiliary * headers and footers. Columns groups are added to {@link ColumnGroupRow}'s. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class ColumnGroup implements Serializable { diff --git a/server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java b/server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java index 5e1ba1100f..a497b5a8a8 100644 --- a/server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java +++ b/server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java @@ -30,7 +30,7 @@ import com.vaadin.shared.ui.grid.ColumnGroupState; * A column group row represents an auxiliary header or footer row added to the * grid. A column group row includes column groups that group columns together. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class ColumnGroupRow implements Serializable { diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 287bd1ddfd..bb5ff23da1 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -72,7 +72,7 @@ import com.vaadin.util.ReflectTools; *

Auxiliary headers and footers

TODO To be revised when column * grouping is implemented. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class Grid extends AbstractComponent implements SelectionChangeNotifier { diff --git a/server/src/com/vaadin/ui/components/grid/GridColumn.java b/server/src/com/vaadin/ui/components/grid/GridColumn.java index cadd621948..43b2003e35 100644 --- a/server/src/com/vaadin/ui/components/grid/GridColumn.java +++ b/server/src/com/vaadin/ui/components/grid/GridColumn.java @@ -29,7 +29,7 @@ import com.vaadin.ui.components.grid.renderers.TextRenderer; * A column in the grid. Can be obtained by calling * {@link Grid#getColumn(Object propertyId)}. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class GridColumn implements Serializable { diff --git a/server/src/com/vaadin/ui/components/grid/Renderer.java b/server/src/com/vaadin/ui/components/grid/Renderer.java index f3d502eb85..b9074fb9f7 100644 --- a/server/src/com/vaadin/ui/components/grid/Renderer.java +++ b/server/src/com/vaadin/ui/components/grid/Renderer.java @@ -28,7 +28,7 @@ import com.vaadin.server.Extension; * @param * the type this renderer knows how to present * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface Renderer extends Extension { diff --git a/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java index e7280f76aa..736b61d9e2 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/DateRenderer.java @@ -24,7 +24,7 @@ import com.vaadin.ui.components.grid.AbstractRenderer; /** * A renderer for presenting date values. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class DateRenderer extends AbstractRenderer { diff --git a/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java index 9c1fbf51d8..6439608c20 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/HtmlRenderer.java @@ -20,7 +20,7 @@ import com.vaadin.ui.components.grid.AbstractRenderer; /** * A renderer for presenting HTML content. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class HtmlRenderer extends AbstractRenderer { diff --git a/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java index d071e592ba..0d1c98d6dc 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/NumberRenderer.java @@ -23,7 +23,7 @@ import com.vaadin.ui.components.grid.AbstractRenderer; /** * A renderer for presenting number values. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class NumberRenderer extends AbstractRenderer { diff --git a/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java b/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java index cdef4e17c8..61348a9e49 100644 --- a/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java +++ b/server/src/com/vaadin/ui/components/grid/renderers/TextRenderer.java @@ -20,7 +20,7 @@ import com.vaadin.ui.components.grid.AbstractRenderer; /** * A renderer for presenting simple plain-text string values. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class TextRenderer extends AbstractRenderer { diff --git a/server/src/com/vaadin/ui/components/grid/selection/AbstractSelectionModel.java b/server/src/com/vaadin/ui/components/grid/selection/AbstractSelectionModel.java index 246ef599b3..e153b8a4e4 100644 --- a/server/src/com/vaadin/ui/components/grid/selection/AbstractSelectionModel.java +++ b/server/src/com/vaadin/ui/components/grid/selection/AbstractSelectionModel.java @@ -25,7 +25,7 @@ import com.vaadin.ui.components.grid.Grid; * A base class for SelectionModels that contains some of the logic that is * reusable. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public abstract class AbstractSelectionModel implements SelectionModel { diff --git a/server/src/com/vaadin/ui/components/grid/selection/MultiSelectionModel.java b/server/src/com/vaadin/ui/components/grid/selection/MultiSelectionModel.java index a196d6ea8c..602e5ca169 100644 --- a/server/src/com/vaadin/ui/components/grid/selection/MultiSelectionModel.java +++ b/server/src/com/vaadin/ui/components/grid/selection/MultiSelectionModel.java @@ -25,7 +25,7 @@ import com.vaadin.data.Container.Indexed; /** * A default implementation of a {@link SelectionModel.Multi} * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class MultiSelectionModel extends AbstractSelectionModel implements diff --git a/server/src/com/vaadin/ui/components/grid/selection/NoSelectionModel.java b/server/src/com/vaadin/ui/components/grid/selection/NoSelectionModel.java index ff5573b522..89c31398ea 100644 --- a/server/src/com/vaadin/ui/components/grid/selection/NoSelectionModel.java +++ b/server/src/com/vaadin/ui/components/grid/selection/NoSelectionModel.java @@ -23,7 +23,7 @@ import com.vaadin.ui.components.grid.Grid; /** * A default implementation for a {@link SelectionModel.None} * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class NoSelectionModel implements SelectionModel.None { diff --git a/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeEvent.java b/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeEvent.java index f0e25405cc..af6a37dfde 100644 --- a/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeEvent.java +++ b/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeEvent.java @@ -27,7 +27,7 @@ import com.vaadin.ui.components.grid.Grid; * An event that specifies what in a selection has changed, and where the * selection took place. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class SelectionChangeEvent extends EventObject { diff --git a/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeListener.java b/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeListener.java index 18fb53e19c..0d10e8c74d 100644 --- a/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeListener.java +++ b/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeListener.java @@ -21,7 +21,7 @@ import java.io.Serializable; * The listener interface for receiving {@link SelectionChangeEvent * SelectionChangeEvents}. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface SelectionChangeListener extends Serializable { diff --git a/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeNotifier.java b/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeNotifier.java index 1a3f0920db..40cef965dd 100644 --- a/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeNotifier.java +++ b/server/src/com/vaadin/ui/components/grid/selection/SelectionChangeNotifier.java @@ -21,7 +21,7 @@ import java.io.Serializable; * The interface for adding and removing listeners for * {@link SelectionChangeEvent SelectionChangeEvents}. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface SelectionChangeNotifier extends Serializable { diff --git a/server/src/com/vaadin/ui/components/grid/selection/SelectionModel.java b/server/src/com/vaadin/ui/components/grid/selection/SelectionModel.java index 2862b8188c..60bb130ab1 100644 --- a/server/src/com/vaadin/ui/components/grid/selection/SelectionModel.java +++ b/server/src/com/vaadin/ui/components/grid/selection/SelectionModel.java @@ -23,7 +23,7 @@ import com.vaadin.ui.components.grid.Grid; /** * The server-side interface that controls Grid's selection state. * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface SelectionModel extends Serializable { diff --git a/server/src/com/vaadin/ui/components/grid/selection/SingleSelectionModel.java b/server/src/com/vaadin/ui/components/grid/selection/SingleSelectionModel.java index 6eaf8d9883..0f6e8a296d 100644 --- a/server/src/com/vaadin/ui/components/grid/selection/SingleSelectionModel.java +++ b/server/src/com/vaadin/ui/components/grid/selection/SingleSelectionModel.java @@ -21,7 +21,7 @@ import java.util.Collections; /** * A default implementation of a {@link SelectionModel.Single} * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class SingleSelectionModel extends AbstractSelectionModel implements diff --git a/shared/src/com/vaadin/shared/data/DataProviderRpc.java b/shared/src/com/vaadin/shared/data/DataProviderRpc.java index 43469914e5..bfd9505c04 100644 --- a/shared/src/com/vaadin/shared/data/DataProviderRpc.java +++ b/shared/src/com/vaadin/shared/data/DataProviderRpc.java @@ -21,7 +21,7 @@ import com.vaadin.shared.communication.ClientRpc; /** * RPC interface used for pushing container data to the client. * - * @since 7.2 + * @since * @author Vaadin Ltd */ public interface DataProviderRpc extends ClientRpc { diff --git a/shared/src/com/vaadin/shared/data/DataProviderState.java b/shared/src/com/vaadin/shared/data/DataProviderState.java index 2eabe0b0e1..13331c2a64 100644 --- a/shared/src/com/vaadin/shared/data/DataProviderState.java +++ b/shared/src/com/vaadin/shared/data/DataProviderState.java @@ -21,7 +21,7 @@ import com.vaadin.shared.communication.SharedState; /** * Shared state used by client-side data sources. * - * @since 7.2 + * @since * @author Vaadin Ltd */ public class DataProviderState extends SharedState { diff --git a/shared/src/com/vaadin/shared/data/DataRequestRpc.java b/shared/src/com/vaadin/shared/data/DataRequestRpc.java index b2a3e6d2ba..80f320e356 100644 --- a/shared/src/com/vaadin/shared/data/DataRequestRpc.java +++ b/shared/src/com/vaadin/shared/data/DataRequestRpc.java @@ -21,7 +21,7 @@ import com.vaadin.shared.communication.ServerRpc; /** * RPC interface used for requesting container data to the client. * - * @since 7.2 + * @since * @author Vaadin Ltd */ public interface DataRequestRpc extends ServerRpc { diff --git a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java index a8e0f87457..d3d5ea2495 100644 --- a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java +++ b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java @@ -23,7 +23,7 @@ import java.util.List; /** * The column group row data shared between the server and client * - * @since 7.2 + * @since * @author Vaadin Ltd */ public class ColumnGroupRowState implements Serializable { diff --git a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java index 3992b6611f..8c2bde851b 100644 --- a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java +++ b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java @@ -23,7 +23,7 @@ import java.util.List; /** * The column group data shared between the server and the client * - * @since 7.2 + * @since * @author Vaadin Ltd */ public class ColumnGroupState implements Serializable { diff --git a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java index 00cc93d371..24a9996d40 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java @@ -20,7 +20,7 @@ import com.vaadin.shared.communication.ClientRpc; /** * Server-to-client RPC interface for the Grid component. * - * @since 7.2 + * @since * @author Vaadin Ltd */ public interface GridClientRpc extends ClientRpc { diff --git a/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java b/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java index d1df08c294..b9bae35db6 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java @@ -23,7 +23,7 @@ import com.vaadin.shared.Connector; * Column state DTO for transferring column properties from the server to the * client * - * @since 7.2 + * @since * @author Vaadin Ltd */ public class GridColumnState implements Serializable { diff --git a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java index 8b264bf426..b098946346 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java @@ -21,7 +21,7 @@ import java.io.Serializable; * Container class for common constants and default values used by the Grid * component. * - * @since 7.2 + * @since * @author Vaadin Ltd */ public final class GridConstants implements Serializable { diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java index b763174e53..eec7b39482 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java @@ -22,7 +22,7 @@ import com.vaadin.shared.communication.ServerRpc; /** * Client-to-server RPC interface for the Grid component * - * @since 7.4 + * @since * @author Vaadin Ltd */ public interface GridServerRpc extends ServerRpc { diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index 3dcf7764ac..f71fe0929a 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -25,7 +25,7 @@ import com.vaadin.shared.annotations.DelegateToWidget; /** * The shared state for the {@link com.vaadin.ui.components.grid.Grid} component * - * @since 7.2 + * @since * @author Vaadin Ltd */ public class GridState extends AbstractComponentState { diff --git a/shared/src/com/vaadin/shared/ui/grid/HeightMode.java b/shared/src/com/vaadin/shared/ui/grid/HeightMode.java index 0146e53e73..09c46b039e 100644 --- a/shared/src/com/vaadin/shared/ui/grid/HeightMode.java +++ b/shared/src/com/vaadin/shared/ui/grid/HeightMode.java @@ -21,7 +21,7 @@ package com.vaadin.shared.ui.grid; * {@link com.vaadin.ui.components.grid.Grid server}) / * {@link com.vaadin.client.ui.grid.Escalator Escalator}. * - * @since 7.2 + * @since * @author Vaadin Ltd * @see com.vaadin.client.ui.grid.Grid#setHeightMode(HeightMode) * @see com.vaadin.ui.components.grid.Grid#setHeightMode(HeightMode) diff --git a/shared/src/com/vaadin/shared/ui/grid/Range.java b/shared/src/com/vaadin/shared/ui/grid/Range.java index c28502256c..a1d4d86103 100644 --- a/shared/src/com/vaadin/shared/ui/grid/Range.java +++ b/shared/src/com/vaadin/shared/ui/grid/Range.java @@ -27,7 +27,7 @@ import java.io.Serializable; * The range is considered {@link #isEmpty() empty} if the start is the same as * the end. * - * @since 7.2 + * @since * @author Vaadin Ltd */ public final class Range implements Serializable { diff --git a/shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java b/shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java index decc2fab5f..5fd69de612 100644 --- a/shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java +++ b/shared/src/com/vaadin/shared/ui/grid/ScrollDestination.java @@ -19,7 +19,7 @@ package com.vaadin.shared.ui.grid; * Enumeration, specifying the destinations that are supported when scrolling * rows or columns into view. * - * @since 7.2 + * @since * @author Vaadin Ltd */ public enum ScrollDestination { diff --git a/shared/src/com/vaadin/shared/ui/grid/SortDirection.java b/shared/src/com/vaadin/shared/ui/grid/SortDirection.java index 3a1828992e..1a7c29f8a7 100644 --- a/shared/src/com/vaadin/shared/ui/grid/SortDirection.java +++ b/shared/src/com/vaadin/shared/ui/grid/SortDirection.java @@ -18,7 +18,7 @@ package com.vaadin.shared.ui.grid; /** * Describes sorting direction for a Grid column * - * @since 7.4 + * @since * @author Vaadin Ltd */ public enum SortDirection { diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index 995188db5c..66eb9ec2d6 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -40,7 +40,7 @@ import com.vaadin.ui.components.grid.renderers.NumberRenderer; /** * Tests the basic features like columns, footers and headers * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class GridBasicFeatures extends AbstractComponentTest { diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index bea941d6a3..e3d3c8c01a 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -36,7 +36,7 @@ import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers; /** * Tests Grid client side renderers * - * @since 7.4 + * @since * @author Vaadin Ltd */ public class GridClientRenderers extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/grid/GridElement.java b/uitest/src/com/vaadin/tests/components/grid/GridElement.java index f743c553d9..091c9db1ce 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridElement.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridElement.java @@ -27,7 +27,7 @@ import com.vaadin.testbench.elements.ServerClass; /** * TestBench Element API for Grid * - * @since 7.4 + * @since * @author Vaadin Ltd */ @ServerClass("com.vaadin.ui.components.grid.Grid") diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java index e2d88c57f2..6dbff5ca66 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java @@ -22,7 +22,7 @@ import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.tests.widgetset.server.grid.TestGrid; /** - * @since 7.2 + * @since * @author Vaadin Ltd */ @Connect(TestGrid.class) diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java index 73d6ba311c..ecbc59552b 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java @@ -18,7 +18,7 @@ package com.vaadin.tests.widgetset.client.grid; import com.vaadin.shared.AbstractComponentState; /** - * @since 7.2 + * @since * @author Vaadin Ltd */ public class TestGridState extends AbstractComponentState { diff --git a/uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java b/uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java index 4e218ebba1..0dbb60359d 100644 --- a/uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java +++ b/uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java @@ -20,7 +20,7 @@ import com.vaadin.tests.widgetset.client.grid.TestGridState; import com.vaadin.ui.AbstractComponent; /** - * @since 7.2 + * @since * @author Vaadin Ltd */ public class TestGrid extends AbstractComponent { -- cgit v1.2.3 From efa97eafaed3a6803535ecb867b1dd90792d233b Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 9 Jul 2014 11:03:08 +0300 Subject: Server-side sorting updates data on client-side (#13334) Change-Id: If4576ed8605c4795d6edaa2f6d36cdb2eb9e8440 --- .../com/vaadin/data/RpcDataProviderExtension.java | 16 +++++-- .../tests/components/grid/GridBasicFeatures.java | 36 ++++++++++++-- .../components/grid/GridBasicFeaturesTest.java | 56 ++++++++++++++++++++-- 3 files changed, 97 insertions(+), 11 deletions(-) (limited to 'uitest/src') diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index 801b925e2a..f731e4575d 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -583,11 +583,17 @@ public class RpcDataProviderExtension extends AbstractExtension { } else { - // TODO no diff info available, redraw everything - throw new UnsupportedOperationException("bare " - + "ItemSetChangeEvents are currently " - + "not supported, use a container that " - + "uses AddItemEvents and RemoveItemEvents."); + Range visibleRows = activeRowHandler.activeRange; + List itemIds = container.getItemIds(visibleRows.getStart(), + visibleRows.length()); + + keyMapper.removeActiveRows(keyMapper.activeRange); + keyMapper.addActiveRows(visibleRows, visibleRows.getStart(), + itemIds); + + pushRows(visibleRows.getStart(), itemIds); + activeRowHandler.setActiveRows(visibleRows.getStart(), + visibleRows.length()); } } }; diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index 66eb9ec2d6..5800c83738 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -23,10 +23,12 @@ 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.util.IndexedContainer; import com.vaadin.shared.ui.grid.HeightMode; +import com.vaadin.shared.ui.grid.SortDirection; import com.vaadin.tests.components.AbstractComponentTest; import com.vaadin.ui.components.grid.ColumnGroup; import com.vaadin.ui.components.grid.ColumnGroupRow; @@ -36,6 +38,8 @@ import com.vaadin.ui.components.grid.GridColumn; 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 @@ -45,9 +49,9 @@ import com.vaadin.ui.components.grid.renderers.NumberRenderer; */ public class GridBasicFeatures extends AbstractComponentTest { - private static final int MANUALLY_FORMATTED_COLUMNS = 3; - private static final int COLUMNS = 10; - private static final int ROWS = 1000; + private static final int MANUALLY_FORMATTED_COLUMNS = 4; + public static final int COLUMNS = 11; + public static final int ROWS = 1000; private int columnGroupRows = 0; private IndexedContainer ds; @@ -78,9 +82,14 @@ public class GridBasicFeatures extends AbstractComponentTest { ds.addContainerProperty(getColumnProperty(col++), Date.class, new Date()); ds.addContainerProperty(getColumnProperty(col++), String.class, ""); + + 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)); @@ -97,6 +106,9 @@ public class GridBasicFeatures extends AbstractComponentTest { // variation item.getItemProperty(getColumnProperty(col++)).setValue( "" + row + ""); + + item.getItemProperty(getColumnProperty(col++)).setValue( + rand.nextInt()); } } @@ -115,6 +127,8 @@ public class GridBasicFeatures extends AbstractComponentTest { new DateRenderer(new SimpleDateFormat("dd.MM.yy HH:mm"))); grid.getColumn(getColumnProperty(col++)).setRenderer( new HtmlRenderer()); + grid.getColumn(getColumnProperty(col++)).setRenderer( + new NumberRenderer()); } // Add footer values (header values are automatically created) @@ -175,6 +189,22 @@ public class GridBasicFeatures extends AbstractComponentTest { grid.setSelectionMode(selectionMode); } }); + + LinkedHashMap> sortableProperties = new LinkedHashMap>(); + 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>() { + @Override + public void execute(Grid grid, List sortOrder, + Object data) { + grid.setSortOrder(sortOrder); + } + }); } protected void createHeaderActions() { diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index 2546def990..d09f55537d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -44,7 +45,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { // Column headers should be visible List cells = getGridHeaderRowCells(); - assertEquals(10, cells.size()); + assertEquals(GridBasicFeatures.COLUMNS, cells.size()); assertEquals("Column0", cells.get(0).getText()); assertEquals("Column1", cells.get(1).getText()); assertEquals("Column2", cells.get(2).getText()); @@ -63,7 +64,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { // Footers should now be visible cells = getGridFooterRowCells(); - assertEquals(10, cells.size()); + assertEquals(GridBasicFeatures.COLUMNS, cells.size()); assertEquals("Footer 0", cells.get(0).getText()); assertEquals("Footer 1", cells.get(1).getText()); assertEquals("Footer 2", cells.get(2).getText()); @@ -86,7 +87,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { // Empty group row cells should be present cells = getGridHeaderRowCells(); - assertEquals(10, cells.size()); + assertEquals(GridBasicFeatures.COLUMNS, cells.size()); // Group columns 0 & 1 selectMenuPath("Component", "Column groups", "Column group row 1", @@ -372,6 +373,55 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { + "back into view", isSelected(getRow(0))); } + @Test + public void testSorting() 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("Column9, DESC"); + String row = ""; + for (int i = 0; i < 3; ++i) { + row += "9"; + assertEquals( + "Grid is not sorted by Column9 using descending direction.", + "(" + row + ", 0)", grid.getCell(i, 0).getText()); + } + + // Column 10 is random numbers from Random with seed 13334 + sortBy("Column10, 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 Column10 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("Column7, DESC"); + for (int i = 0; i < 3; ++i) { + assertEquals( + "Grid is not sorted by Column7 using descending direction", + "(" + i + ", 0)", + grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText()); + } + } + + private void sortBy(String column) { + selectMenuPath("Component", "State", "Sort by column", column); + } + private void toggleFirstRowSelection() { selectMenuPath("Component", "Body rows", "Select first row"); } -- cgit v1.2.3 From aba7d2b2285865cd86cbdc722732cc0657b44634 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 10 Jul 2014 11:56:40 +0300 Subject: Fix modifying rows in GridBasicFeatures Change-Id: If19200b02720a7fe3a0b2bd1e944f21aa12bdb98 --- .../tests/components/grid/GridBasicFeatures.java | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index 5800c83738..a7dad4795f 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -26,6 +26,7 @@ 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.HeightMode; import com.vaadin.shared.ui.grid.SortDirection; @@ -420,27 +421,37 @@ public class GridBasicFeatures extends AbstractComponentTest { createClickAction("Modify first row (getItemProperty)", "Body rows", new Command() { + @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++) { - item.getItemProperty(getColumnProperty(i)) - .setValue("modified: " + i); + Property property = item + .getItemProperty(getColumnProperty(i)); + if (property.getType().equals(String.class)) { + ((Property) property) + .setValue("modified: " + i); + } } } }, null); createClickAction("Modify first row (getContainerProperty)", "Body rows", new Command() { + @SuppressWarnings("unchecked") @Override public void execute(Grid c, String value, Object data) { Object firstItemId = ds.getIdByIndex(0); for (Object containerPropertyId : ds .getContainerPropertyIds()) { - ds.getContainerProperty(firstItemId, - containerPropertyId).setValue( - "modified: " + containerPropertyId); + Property property = ds.getContainerProperty( + firstItemId, containerPropertyId); + if (property.getType().equals(String.class)) { + ((Property) property) + .setValue("modified: " + + containerPropertyId); + } } } }, null); -- cgit v1.2.3 From b36c0fc7e01def912430be5d9a42d344d8202046 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 9 Jul 2014 19:20:19 +0300 Subject: GridConnector sends user sort events to the server (#13334) Change-Id: Ic5b1462ecf2e5a5cef6b08bea7a4c00a09c39c9a --- .../com/vaadin/client/ui/grid/GridConnector.java | 22 +++++++++ server/src/com/vaadin/ui/components/grid/Grid.java | 14 ++++++ .../com/vaadin/shared/ui/grid/GridServerRpc.java | 2 + .../components/grid/GridBasicFeaturesTest.java | 53 +++++++++++++++++++++- 4 files changed, 90 insertions(+), 1 deletion(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index dd27f7f747..095b049506 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -42,6 +42,9 @@ import com.vaadin.client.ui.grid.selection.SelectionChangeHandler; import com.vaadin.client.ui.grid.selection.SelectionModelMulti; import com.vaadin.client.ui.grid.selection.SelectionModelNone; import com.vaadin.client.ui.grid.selection.SelectionModelSingle; +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.shared.ui.grid.ColumnGroupRowState; import com.vaadin.shared.ui.grid.ColumnGroupState; @@ -51,6 +54,7 @@ import com.vaadin.shared.ui.grid.GridServerRpc; import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.GridState.SharedSelectionMode; import com.vaadin.shared.ui.grid.ScrollDestination; +import com.vaadin.shared.ui.grid.SortDirection; /** * Connects the client side {@link Grid} widget with the server side @@ -257,6 +261,24 @@ public class GridConnector extends AbstractComponentConnector { getWidget().addSelectionChangeHandler(internalSelectionChangeHandler); + getWidget().addSortHandler(new SortEventHandler() { + @Override + public void sort(SortEvent event) { + List order = event.getOrder(); + String[] columnIds = new String[order.size()]; + SortDirection[] directions = new SortDirection[order.size()]; + for (int i = 0; i < order.size(); i++) { + SortOrder sortOrder = order.get(i); + CustomGridColumn column = (CustomGridColumn) sortOrder + .getColumn(); + columnIds[i] = column.id; + + directions[i] = sortOrder.getDirection(); + } + + getRpcProxy(GridServerRpc.class).sort(columnIds, directions); + } + }); } @Override diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 1d9cb8ef10..cc284841a1 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -315,6 +315,20 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { } } } + + @Override + public void sort(String[] columnIds, SortDirection[] directions) { + assert columnIds.length == directions.length; + + List order = new ArrayList( + columnIds.length); + for (int i = 0; i < columnIds.length; i++) { + Object propertyId = getPropertyIdByColumnId(columnIds[i]); + order.add(new SortOrder(propertyId, directions[i])); + } + + setSortOrder(order); + } }); } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java index eec7b39482..9ce094b092 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java @@ -27,4 +27,6 @@ import com.vaadin.shared.communication.ServerRpc; */ public interface GridServerRpc extends ServerRpc { void selectionChange(List newSelection); + + void sort(String[] columnIds, SortDirection[] directions); } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index d09f55537d..59f6311995 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -374,7 +374,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { } @Test - public void testSorting() throws IOException { + public void testProgrammaticSorting() throws IOException { openTestURL(); GridElement grid = getGridElement(); @@ -418,6 +418,57 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { } } + @Test + public void testUserSorting() { + 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 Column9 using descending direction.", + "(" + row + ", 0)", grid.getCell(i, 0).getText()); + } + + // Column 10 is random numbers from Random with seed 13334 + // Click header to sort ascending + grid.getHeaderCell(0, 10).click(); + + // 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 Column10 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 Column7 using descending direction", + "(" + i + ", 0)", + grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText()); + } + } + private void sortBy(String column) { selectMenuPath("Component", "State", "Sort by column", column); } -- cgit v1.2.3 From f8d87110461bee9b7056858750d1fd6a19e2a5d6 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 10 Jul 2014 08:57:21 +0300 Subject: Add server-side SortOrderChangeEvent support (#13334) Change-Id: Ia250909edccf9a838414994ee24eb5326f49478a --- server/src/com/vaadin/ui/components/grid/Grid.java | 31 ++++++++++++ .../ui/components/grid/SortOrderChangeEvent.java | 57 ++++++++++++++++++++++ .../components/grid/SortOrderChangeListener.java | 34 +++++++++++++ .../vaadin/ui/components/grid/sort/SortOrder.java | 41 ++++++++++++++-- .../tests/server/component/grid/sort/SortTest.java | 49 +++++++++++++++++++ .../tests/components/grid/GridBasicFeatures.java | 9 ++++ .../components/grid/GridBasicFeaturesTest.java | 10 +++- 7 files changed, 226 insertions(+), 5 deletions(-) create mode 100644 server/src/com/vaadin/ui/components/grid/SortOrderChangeEvent.java create mode 100644 server/src/com/vaadin/ui/components/grid/SortOrderChangeListener.java (limited to 'uitest/src') diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index cc284841a1..79effadab9 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -211,6 +211,10 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { .findMethod(SelectionChangeListener.class, "selectionChange", SelectionChangeEvent.class); + private static final Method SORT_ORDER_CHANGE_METHOD = ReflectTools + .findMethod(SortOrderChangeListener.class, "sortOrderChange", + SortOrderChangeEvent.class); + /** * Creates a new Grid using the given datasource. * @@ -1252,9 +1256,36 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { } cs.sort(propertyIds, directions); + + fireEvent(new SortOrderChangeEvent(this, new ArrayList( + sortOrder))); } else { throw new IllegalStateException( "Container is not sortable (does not implement Container.Sortable)"); } } + + /** + * Adds a sort order change listener that gets notified when the sort order + * changes. + * + * @param listener + * the sort order change listener to add + */ + public void addSortOrderChangeListener(SortOrderChangeListener listener) { + addListener(SortOrderChangeEvent.class, listener, + SORT_ORDER_CHANGE_METHOD); + } + + /** + * Removes a sort order change listener previously added using + * {@link #addSortOrderChangeListener(SortOrderChangeListener)}. + * + * @param listener + * the sort order change listener to remove + */ + public void removeSortOrderChangeListener(SortOrderChangeListener listener) { + removeListener(SortOrderChangeEvent.class, listener, + SORT_ORDER_CHANGE_METHOD); + } } diff --git a/server/src/com/vaadin/ui/components/grid/SortOrderChangeEvent.java b/server/src/com/vaadin/ui/components/grid/SortOrderChangeEvent.java new file mode 100644 index 0000000000..71afa10a9b --- /dev/null +++ b/server/src/com/vaadin/ui/components/grid/SortOrderChangeEvent.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.grid; + +import java.util.List; + +import com.vaadin.ui.Component; +import com.vaadin.ui.components.grid.sort.SortOrder; + +/** + * Event fired by {@link Grid} when the sort order has changed. + * + * @see SortOrderChangeListener + * + * @since + * @author Vaadin Ltd + */ +public class SortOrderChangeEvent extends Component.Event { + + private final List sortOrder; + + /** + * Creates a new sort order change event for a grid and a sort order list. + * + * @param grid + * the grid from which the event originates + * @param sortOrder + * the new sort order list + */ + public SortOrderChangeEvent(Grid grid, List sortOrder) { + super(grid); + this.sortOrder = sortOrder; + } + + /** + * Gets the sort order list. + * + * @return the sort order list + */ + public List getSortOrder() { + return sortOrder; + } + +} diff --git a/server/src/com/vaadin/ui/components/grid/SortOrderChangeListener.java b/server/src/com/vaadin/ui/components/grid/SortOrderChangeListener.java new file mode 100644 index 0000000000..82d7ba3108 --- /dev/null +++ b/server/src/com/vaadin/ui/components/grid/SortOrderChangeListener.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.grid; + +import java.io.Serializable; + +/** + * Listener for sort order change events from {@link Grid}. + * + * @since + * @author Vaadin Ltd + */ +public interface SortOrderChangeListener extends Serializable { + /** + * Called when the sort order has changed. + * + * @param event + * the sort order change event + */ + public void sortOrderChange(SortOrderChangeEvent event); +} diff --git a/server/src/com/vaadin/ui/components/grid/sort/SortOrder.java b/server/src/com/vaadin/ui/components/grid/sort/SortOrder.java index f186333e0a..a76148fe0c 100644 --- a/server/src/com/vaadin/ui/components/grid/sort/SortOrder.java +++ b/server/src/com/vaadin/ui/components/grid/sort/SortOrder.java @@ -22,7 +22,7 @@ import com.vaadin.shared.ui.grid.SortDirection; /** * Sort order descriptor. Links together a {@link SortDirection} value and a * Vaadin container property ID. - * + * * @since 7.4 * @author Vaadin Ltd */ @@ -33,7 +33,7 @@ public class SortOrder implements Serializable { /** * Create a SortOrder object. Both arguments must be non-null. - * + * * @param propertyId * id of the data source property to sort by * @param direction @@ -54,7 +54,7 @@ public class SortOrder implements Serializable { /** * Returns the property ID. - * + * * @return a property ID */ public Object getPropertyId() { @@ -63,11 +63,44 @@ public class SortOrder implements Serializable { /** * Returns the {@link SortDirection} value. - * + * * @return a sort direction value */ public SortDirection getDirection() { return direction; } + @Override + public String toString() { + return propertyId + " " + direction; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + direction.hashCode(); + result = prime * result + propertyId.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj == null) { + return false; + } else if (getClass() != obj.getClass()) { + return false; + } + + SortOrder other = (SortOrder) obj; + if (direction != other.direction) { + return false; + } else if (!propertyId.equals(other.propertyId)) { + return false; + } + return true; + } + } diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/sort/SortTest.java b/server/tests/src/com/vaadin/tests/server/component/grid/sort/SortTest.java index 844292265d..d3a9315e20 100644 --- a/server/tests/src/com/vaadin/tests/server/component/grid/sort/SortTest.java +++ b/server/tests/src/com/vaadin/tests/server/component/grid/sort/SortTest.java @@ -15,6 +15,9 @@ */ package com.vaadin.tests.server.component.grid.sort; +import java.util.Arrays; +import java.util.List; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -23,7 +26,10 @@ import org.junit.Test; import com.vaadin.data.util.IndexedContainer; import com.vaadin.shared.ui.grid.SortDirection; import com.vaadin.ui.components.grid.Grid; +import com.vaadin.ui.components.grid.SortOrderChangeEvent; +import com.vaadin.ui.components.grid.SortOrderChangeListener; import com.vaadin.ui.components.grid.sort.Sort; +import com.vaadin.ui.components.grid.sort.SortOrder; public class SortTest { @@ -65,14 +71,38 @@ public class SortTest { } } + class RegisteringSortChangeListener implements SortOrderChangeListener { + private List order; + + @Override + public void sortOrderChange(SortOrderChangeEvent event) { + assert order == null : "The same listener was notified multipe times without checking"; + + order = event.getSortOrder(); + } + + public void assertEventFired(SortOrder... expectedOrder) { + Assert.assertEquals(Arrays.asList(expectedOrder), order); + + // Reset for nest test + order = null; + } + + } + private DummySortingIndexedContainer container; + private RegisteringSortChangeListener listener; private Grid grid; @Before public void setUp() { container = createContainer(); container.expectedSort(new Object[] {}, new SortDirection[] {}); + + listener = new RegisteringSortChangeListener(); + grid = new Grid(container); + grid.addSortOrderChangeListener(listener); } @After @@ -107,6 +137,8 @@ public class SortTest { container.expectedSort(new Object[] { "foo" }, new SortDirection[] { SortDirection.ASCENDING }); grid.sort("foo"); + + listener.assertEventFired(new SortOrder("foo", SortDirection.ASCENDING)); } @Test @@ -114,6 +146,8 @@ public class SortTest { container.expectedSort(new Object[] { "foo" }, new SortDirection[] { SortDirection.DESCENDING }); grid.sort("foo", SortDirection.DESCENDING); + + listener.assertEventFired(new SortOrder("foo", SortDirection.DESCENDING)); } @Test @@ -123,6 +157,12 @@ public class SortTest { SortDirection.ASCENDING, SortDirection.DESCENDING }); grid.sort(Sort.by("foo").then("bar") .then("baz", SortDirection.DESCENDING)); + + listener.assertEventFired( + new SortOrder("foo", SortDirection.ASCENDING), new SortOrder( + "bar", SortDirection.ASCENDING), new SortOrder("baz", + SortDirection.DESCENDING)); + } @Test @@ -132,11 +172,20 @@ public class SortTest { SortDirection.ASCENDING, SortDirection.DESCENDING }); grid.sort(Sort.by("foo").then("bar") .then("baz", SortDirection.DESCENDING)); + + listener.assertEventFired( + new SortOrder("foo", SortDirection.ASCENDING), new SortOrder( + "bar", SortDirection.ASCENDING), new SortOrder("baz", + SortDirection.DESCENDING)); + container = new DummySortingIndexedContainer(); container.addContainerProperty("baz", String.class, ""); container.expectedSort(new Object[] { "baz" }, new SortDirection[] { SortDirection.DESCENDING }); grid.setContainerDataSource(container); + + listener.assertEventFired(new SortOrder("baz", SortDirection.DESCENDING)); + } private DummySortingIndexedContainer createContainer() { diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java index a7dad4795f..6e4bafc797 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java @@ -36,6 +36,8 @@ import com.vaadin.ui.components.grid.ColumnGroupRow; 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.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; @@ -143,6 +145,13 @@ public class GridBasicFeatures extends AbstractComponentTest { grid.getColumn("Column" + col).setWidth(100 + col * 50); } + grid.addSortOrderChangeListener(new SortOrderChangeListener() { + @Override + public void sortOrderChange(SortOrderChangeEvent event) { + log("Sort order: " + event.getSortOrder()); + } + }); + grid.setSelectionMode(SelectionMode.NONE); createGridActions(); diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index 59f6311995..f15f45f97a 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -419,7 +419,7 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { } @Test - public void testUserSorting() { + public void testUserSorting() throws InterruptedException { openTestURL(); GridElement grid = getGridElement(); @@ -439,10 +439,15 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { "(" + row + ", 0)", grid.getCell(i, 0).getText()); } + assertEquals("2. Sort order: [Column9 ASCENDING]", getLogRow(2)); + assertEquals("4. Sort order: [Column9 DESCENDING]", 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: [Column10 ASCENDING]", getLogRow(0)); + // Not cleaning up correctly causes exceptions when scrolling. grid.scrollToRow(50); assertFalse("Scrolling caused and exception when shuffled.", @@ -467,6 +472,9 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { "(" + i + ", 0)", grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText()); } + + assertEquals("9. Sort order: [Column7 ASCENDING]", getLogRow(3)); + assertEquals("11. Sort order: [Column7 DESCENDING]", getLogRow(1)); } private void sortBy(String column) { -- cgit v1.2.3 From f27a00b7b9a487a66dd23a4d28aa56fe60a1ad4e Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 10 Jul 2014 15:41:24 +0300 Subject: Server-side programmatic sort updates sort indicators in the UI (#13334) Change-Id: Ia4bae5d88d265250d1bf4daa8d23561edb757872 --- .../com/vaadin/client/ui/grid/GridConnector.java | 23 +++++++++++++++++++++- server/src/com/vaadin/ui/components/grid/Grid.java | 10 ++++++++++ .../src/com/vaadin/shared/ui/grid/GridState.java | 6 ++++++ .../components/grid/GridBasicFeaturesTest.java | 22 +++++++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 095b049506..ca66ccc3d5 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -17,6 +17,7 @@ package com.vaadin.client.ui.grid; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -276,7 +277,12 @@ public class GridConnector extends AbstractComponentConnector { directions[i] = sortOrder.getDirection(); } - getRpcProxy(GridServerRpc.class).sort(columnIds, directions); + if (!Arrays.equals(columnIds, getState().sortColumns) + || !Arrays.equals(directions, getState().sortDirs)) { + // Report back to server if changed + getRpcProxy(GridServerRpc.class) + .sort(columnIds, directions); + } } }); } @@ -522,6 +528,21 @@ public class GridConnector extends AbstractComponentConnector { } + @OnStateChange({ "sortColumns", "sortDirs" }) + void onSortStateChange() { + List sortOrder = new ArrayList(); + + String[] sortColumns = getState().sortColumns; + SortDirection[] sortDirs = getState().sortDirs; + + for (int i = 0; i < sortColumns.length; i++) { + sortOrder.add(new SortOrder(columnIdToColumn.get(sortColumns[i]), + sortDirs[i])); + } + + getWidget().setSortOrder(sortOrder); + } + private Logger getLogger() { return Logger.getLogger(getClass().getName()); } diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 79effadab9..f18ca6045e 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -1239,8 +1239,15 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { Object[] propertyIds = new Object[items]; boolean[] directions = new boolean[items]; + String[] columnKeys = new String[items]; + SortDirection[] stateDirs = new SortDirection[items]; + for (int i = 0; i < items; ++i) { SortOrder order = sortOrder.get(i); + + columnKeys[i] = this.columnKeys.key(order.getPropertyId()); + stateDirs[i] = order.getDirection(); + propertyIds[i] = order.getPropertyId(); switch (order.getDirection()) { case ASCENDING: @@ -1259,6 +1266,9 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { fireEvent(new SortOrderChangeEvent(this, new ArrayList( sortOrder))); + + getState().sortColumns = columnKeys; + getState(false).sortDirs = stateDirs; } else { throw new IllegalStateException( "Container is not sortable (does not implement Container.Sortable)"); diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index f71fe0929a..ef1b9a806a 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -132,4 +132,10 @@ public class GridState extends AbstractComponentState { public List selectedKeys = new ArrayList(); public SharedSelectionMode selectionMode; + + /** Keys of the currently sorted columns */ + public String[] sortColumns = new String[0]; + + /** Directions for each sorted column */ + public SortDirection[] sortDirs = new SortDirection[0]; } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java index f15f45f97a..a94550721e 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java @@ -383,6 +383,11 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { // String. // First cells for first 3 rows are (9, 0), (99, 0) and (999, 0) sortBy("Column9, DESC"); + + 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"; @@ -394,6 +399,14 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { // Column 10 is random numbers from Random with seed 13334 sortBy("Column10, 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.", @@ -416,6 +429,15 @@ public class GridBasicFeaturesTest extends MultiBrowserTest { "(" + 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 -- cgit v1.2.3 From 5c931588582025e983ef457b503a1d3c2e6d41b2 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Thu, 10 Jul 2014 16:26:01 +0300 Subject: Generate type data for AbstractRendererConnector.createRenderer (#13334) The declared return type of the most-derived getRenderer method is stored to make the default createRenderer implementation work. This is identical to the way AbstractComponentConnector getWidget and createWidget work. Change-Id: I879e9e6739e366bd81773a1e65195336e0cdac6d --- .../ConnectorBundleLoaderFactory.java | 6 ++- .../widgetsetutils/metadata/ConnectorBundle.java | 6 +++ .../metadata/RendererInitVisitor.java | 63 ++++++++++++++++++++++ .../ui/grid/renderers/TextRendererConnector.java | 5 -- .../renderers/UnsafeHtmlRendererConnector.java | 7 +-- .../client/grid/IntArrayRendererConnector.java | 6 +-- .../client/grid/RowAwareRendererConnector.java | 2 + 7 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererInitVisitor.java (limited to 'uitest/src') diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java index 5519dd1aae..e02317be78 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java @@ -61,6 +61,7 @@ import com.vaadin.server.widgetsetutils.metadata.ConnectorInitVisitor; import com.vaadin.server.widgetsetutils.metadata.GeneratedSerializer; import com.vaadin.server.widgetsetutils.metadata.OnStateChangeVisitor; import com.vaadin.server.widgetsetutils.metadata.Property; +import com.vaadin.server.widgetsetutils.metadata.RendererInitVisitor; import com.vaadin.server.widgetsetutils.metadata.ServerRpcVisitor; import com.vaadin.server.widgetsetutils.metadata.StateInitVisitor; import com.vaadin.server.widgetsetutils.metadata.TypeVisitor; @@ -1235,8 +1236,9 @@ public class ConnectorBundleLoaderFactory extends Generator { throws NotFoundException { List visitors = Arrays. asList( new ConnectorInitVisitor(), new StateInitVisitor(), - new WidgetInitVisitor(), new ClientRpcVisitor(), - new ServerRpcVisitor(), new OnStateChangeVisitor()); + new WidgetInitVisitor(), new RendererInitVisitor(), + new ClientRpcVisitor(), new ServerRpcVisitor(), + new OnStateChangeVisitor()); for (TypeVisitor typeVisitor : visitors) { typeVisitor.init(oracle); } diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java index 8bbcac4ecb..463bf00027 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java @@ -43,6 +43,7 @@ import com.vaadin.client.ComponentConnector; import com.vaadin.client.ServerConnector; import com.vaadin.client.communication.JSONSerializer; import com.vaadin.client.ui.UnknownComponentConnector; +import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; import com.vaadin.shared.communication.ClientRpc; import com.vaadin.shared.communication.ServerRpc; import com.vaadin.shared.ui.Connect; @@ -414,6 +415,11 @@ public class ConnectorBundle { return isConnected(type) && isType(type, ComponentConnector.class); } + public static boolean isConnectedRendererConnector(JClassType type) { + return isConnected(type) + && isType(type, AbstractRendererConnector.class); + } + private static boolean isInterfaceType(JClassType type, Class class1) { return type.isInterface() != null && isType(type, class1); } diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererInitVisitor.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererInitVisitor.java new file mode 100644 index 0000000000..ec68f05b8f --- /dev/null +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererInitVisitor.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.server.widgetsetutils.metadata; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; + +/** + * Generates type data for renderer connectors. Specifically, stores the return + * type of the overridden {@link AbstractRendererConnector#getRenderer() + * getRenderer} method to enable automatic creation of an instance of the proper + * renderer type. + * + * @see WidgetInitVisitor + * + * @since + * @author Vaadin Ltd + */ +public class RendererInitVisitor extends TypeVisitor { + + @Override + public void visitConnector(TreeLogger logger, JClassType type, + ConnectorBundle bundle) throws UnableToCompleteException { + + if (ConnectorBundle.isConnectedRendererConnector(type)) { + + // The class in which createRenderer is implemented + JClassType createRendererClass = ConnectorBundle + .findInheritedMethod(type, "createRenderer") + .getEnclosingType(); + + JMethod getRenderer = ConnectorBundle.findInheritedMethod(type, + "getRenderer"); + JClassType rendererType = getRenderer.getReturnType().isClass(); + + // Needs GWT constructor if createRenderer is not overridden + if (createRendererClass.getQualifiedSourceName().equals( + AbstractRendererConnector.class.getCanonicalName())) { + + bundle.setNeedsGwtConstructor(rendererType); + + // Also needs renderer type to find the right GWT constructor + bundle.setNeedsReturnType(type, getRenderer); + } + } + } +} diff --git a/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java index 18cc84cd34..84b261415b 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java @@ -31,11 +31,6 @@ public class TextRendererConnector extends AbstractRendererConnector { return (TextRenderer) super.getRenderer(); } - @Override - public TextRenderer createRenderer() { - return new TextRenderer(); - } - @Override public Class getType() { return String.class; diff --git a/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java index 1816ac974a..7d5b9e1c60 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java @@ -29,7 +29,7 @@ import com.vaadin.shared.ui.Connect; public class UnsafeHtmlRendererConnector extends AbstractRendererConnector { - public class UnsafeHtmlRenderer implements Renderer { + public static class UnsafeHtmlRenderer implements Renderer { @Override public void render(FlyweightCell cell, String data) { cell.getElement().setInnerHTML(data); @@ -41,11 +41,6 @@ public class UnsafeHtmlRendererConnector extends return (UnsafeHtmlRenderer) super.getRenderer(); } - @Override - protected UnsafeHtmlRenderer createRenderer() { - return new UnsafeHtmlRenderer(); - } - @Override public Class getType() { return String.class; diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java index be358c2738..dc424e7606 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java @@ -23,7 +23,7 @@ import com.vaadin.shared.ui.Connect; @Connect(com.vaadin.tests.components.grid.IntArrayRenderer.class) public class IntArrayRendererConnector extends AbstractRendererConnector { - public class IntArrayRenderer implements Renderer { + public static class IntArrayRenderer implements Renderer { private static final String JOINER = " :: "; @Override @@ -40,8 +40,8 @@ public class IntArrayRendererConnector extends AbstractRendererConnector } @Override - protected IntArrayRenderer createRenderer() { - return new IntArrayRenderer(); + public IntArrayRenderer getRenderer() { + return (IntArrayRenderer) super.getRenderer(); } @Override diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java index c82c6c9a18..40dbbeb370 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java @@ -73,6 +73,8 @@ public class RowAwareRendererConnector extends AbstractRendererConnector { @Override protected Renderer createRenderer() { + // cannot use the default createRenderer as RowAwareRenderer needs a + // reference to its connector - it has no "real" no-argument constructor return new RowAwareRenderer(); } } -- cgit v1.2.3 From 04e73909e080f32f7af43caf3029a8033a6acac4 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 10 Jul 2014 16:57:48 +0300 Subject: Add TestCategory annotation for GridClientRenderers test Change-Id: I239947c9538a2f2c2b937f50d863e7fb612fe5a2 --- uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index e3d3c8c01a..d1aec66dbd 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -29,6 +29,7 @@ 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.tb3.MultiBrowserTest; import com.vaadin.tests.widgetset.client.grid.GridClientColumnRendererConnector.Renderers; import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers; @@ -39,6 +40,7 @@ import com.vaadin.tests.widgetset.server.grid.GridClientColumnRenderers; * @since * @author Vaadin Ltd */ +@TestCategory("grid") public class GridClientRenderers extends MultiBrowserTest { private static final double SLEEP_MULTIPLIER = 1.2; -- cgit v1.2.3 From 3582b43415c7ddd587451f565a5ae70fea8bb51d Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 15 Jul 2014 12:53:02 +0300 Subject: Rename scrollToItem to scrollTo (#13334) Change-Id: Ib2e9415a40ec1664ea0b9881437f1c33eaf0bc09 --- server/src/com/vaadin/ui/components/grid/Grid.java | 6 +++--- uitest/src/com/vaadin/tests/components/grid/GridScrolling.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'uitest/src') diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index f18ca6045e..c91924f5a8 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -713,8 +713,8 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * @throws IllegalArgumentException * if the provided id is not recognized by the data source. */ - public void scrollToItem(Object itemId) throws IllegalArgumentException { - scrollToItem(itemId, ScrollDestination.ANY); + public void scrollTo(Object itemId) throws IllegalArgumentException { + scrollTo(itemId, ScrollDestination.ANY); } /** @@ -727,7 +727,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * @throws IllegalArgumentException * if the provided id is not recognized by the data source. */ - public void scrollToItem(Object itemId, ScrollDestination destination) + public void scrollTo(Object itemId, ScrollDestination destination) throws IllegalArgumentException { int row = datasource.indexOfId(itemId); diff --git a/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java b/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java index e8b327639b..dd86d616b9 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridScrolling.java @@ -78,7 +78,7 @@ public class GridScrolling extends AbstractTestUI { new ClickListener() { @Override public void buttonClick(ClickEvent event) { - grid.scrollToItem(Integer.valueOf(row), + grid.scrollTo(Integer.valueOf(row), ScrollDestination.MIDDLE); } }); -- cgit v1.2.3 From f89d015e9252d4470afa6008fd3f004809129b89 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 14 Jul 2014 16:40:30 +0300 Subject: Implement active cell painting and mouse interaction (#13334) Change-Id: Iecb9db0fe6ea9ef0409e2ac0a294ac3508277251 --- WebContent/VAADIN/themes/base/grid/grid.scss | 13 +++- client/src/com/vaadin/client/ui/grid/Grid.java | 91 ++++++++++++++++++++-- .../client/ui/grid/renderers/ComplexRenderer.java | 8 +- .../ui/grid/selection/MultiSelectionRenderer.java | 3 +- .../grid/GridKeyboardNavigationTest.java | 66 ++++++++++++++++ .../client/grid/RowAwareRendererConnector.java | 3 +- 6 files changed, 172 insertions(+), 12 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java (limited to 'uitest/src') diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index 2955f7ecd3..88c7754a10 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -19,8 +19,19 @@ right: 5px; } + .#{$primaryStyleName}-cell-active { + border-color: blue; + } + + .#{$primaryStyleName}-header-active { + background: lightgray; + } + + .#{$primaryStyleName}-row-active > td { + background: rgb(244,244,244); + } } - + .#{$primaryStyleName}-row-selected > td { background: lightblue; } diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index d03197e2ef..471f62cdeb 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -235,12 +235,21 @@ public class Grid extends Composite implements private String rowHasDataStyleName; private String rowSelectedStyleName; + private String cellActiveStyleName; + private String rowActiveStyleName; + private String headerFooterFocusedStyleName; /** * Current selection model. */ private SelectionModel selectionModel; + /** + * Current active cell. + */ + private int activeRow = 0; + private int activeColumn = 0; + /** * Enumeration for easy setting of selection mode. */ @@ -430,14 +439,14 @@ public class Grid extends Composite implements } @Override - public void onBrowserEvent(final Cell cell, NativeEvent event) { + public boolean onBrowserEvent(final Cell cell, NativeEvent event) { // Handle sorting events if column is sortable if (grid.getColumn(cell.getColumn()).isSortable()) { if (BrowserEvents.TOUCHSTART.equals(event.getType())) { if (event.getTouches().length() > 1) { - return; + return false; } event.preventDefault(); @@ -452,7 +461,7 @@ public class Grid extends Composite implements } else if (BrowserEvents.TOUCHMOVE.equals(event.getType())) { if (event.getTouches().length() > 1) { - return; + return false; } event.preventDefault(); @@ -472,7 +481,7 @@ public class Grid extends Composite implements } else if (BrowserEvents.TOUCHEND.equals(event.getType())) { if (event.getTouches().length() > 0) { - return; + return false; } if (lazySorter.isRunning()) { @@ -485,7 +494,7 @@ public class Grid extends Composite implements } else if (BrowserEvents.TOUCHCANCEL .equals(event.getType())) { if (event.getChangedTouches().length() > 1) { - return; + return false; } lazySorter.cancel(); @@ -496,7 +505,10 @@ public class Grid extends Composite implements lazySorter.setMultisort(event.getShiftKey()); lazySorter.run(); } + return true; } + return false; + } /** @@ -986,6 +998,10 @@ public class Grid extends Composite implements getRenderer(column) .render(cell, getColumnValue(column)); } + + setStyleName(cell.getElement(), + headerFooterFocusedStyleName, + activeColumn == cell.getColumn()); } } else if (columnGroupRows.size() > 0) { @@ -1023,6 +1039,10 @@ public class Grid extends Composite implements // Cells are reused cellElement.setInnerHTML(null); cell.setColSpan(1); + + setStyleName(cell.getElement(), + headerFooterFocusedStyleName, + activeColumn == cell.getColumn()); } } } @@ -1060,6 +1080,7 @@ public class Grid extends Composite implements refreshHeader(); refreshFooter(); + sinkEvents(Event.ONMOUSEDOWN); setSelectionMode(SelectionMode.SINGLE); escalator @@ -1092,6 +1113,9 @@ public class Grid extends Composite implements escalator.setStylePrimaryName(style); rowHasDataStyleName = getStylePrimaryName() + "-row-has-data"; rowSelectedStyleName = getStylePrimaryName() + "-row-selected"; + cellActiveStyleName = getStylePrimaryName() + "-cell-active"; + headerFooterFocusedStyleName = getStylePrimaryName() + "-header-active"; + rowActiveStyleName = getStylePrimaryName() + "-row-active"; } /** @@ -1194,6 +1218,9 @@ public class Grid extends Composite implements setStyleName(rowElement, rowSelectedStyleName, false); } + setStyleName(rowElement, rowActiveStyleName, + rowIndex == activeRow); + for (FlyweightCell cell : cellsToUpdate) { GridColumn column = getColumnFromVisibleIndex(cell .getColumn()); @@ -1201,6 +1228,9 @@ public class Grid extends Composite implements assert column != null : "Column was not found from cell (" + cell.getColumn() + "," + cell.getRow() + ")"; + setStyleName(cell.getElement(), cellActiveStyleName, + isActiveCell(cell)); + Renderer renderer = column.getRenderer(); // Hide cell content if needed @@ -1232,6 +1262,11 @@ public class Grid extends Composite implements } } + private boolean isActiveCell(FlyweightCell cell) { + return cell.getRow() == activeRow + && cell.getColumn() == activeColumn; + } + @Override public void preDetach(Row row, Iterable cellsToDetach) { for (FlyweightCell cell : cellsToDetach) { @@ -2095,8 +2130,19 @@ public class Grid extends Composite implements } if (renderer instanceof ComplexRenderer) { - ((ComplexRenderer) renderer).onBrowserEvent(cell, - event); + ComplexRenderer cplxRenderer = (ComplexRenderer) renderer; + if (cplxRenderer.getConsumedEvents().contains( + event.getType())) { + if (cplxRenderer.onBrowserEvent(cell, event)) { + return; + } + } + } + + // TODO: Support active cells in Headers and Footers, + // 14.07.2014, Teemu Suo-Anttila + if (event.getTypeInt() == Event.ONMOUSEDOWN) { + setActiveCell(cell); } } } @@ -2202,11 +2248,13 @@ public class Grid extends Composite implements if (this.selectColumnRenderer != null) { removeColumnSkipSelectionColumnCheck(selectionColumn); + --activeColumn; } this.selectColumnRenderer = selectColumnRenderer; if (selectColumnRenderer != null) { + ++activeColumn; selectionColumn = new SelectionColumn(selectColumnRenderer); // FIXME: this needs to be done elsewhere, requires design... @@ -2215,6 +2263,7 @@ public class Grid extends Composite implements selectionColumn.initDone(); } else { selectionColumn = null; + refreshBody(); } } @@ -2452,4 +2501,32 @@ public class Grid extends Composite implements fireEvent(new SortEvent(this, Collections.unmodifiableList(sortOrder))); } + + /** + * Set currently active cell used for keyboard navigation. Note that active + * cell is not {@code activeElement}. + * + * @param cell + * a cell object + */ + public void setActiveCell(Cell cell) { + int oldRow = activeRow; + int oldColumn = activeColumn; + + activeRow = cell.getRow(); + activeColumn = cell.getColumn(); + + if (oldRow != activeRow) { + escalator.getBody().refreshRows(oldRow, 1); + escalator.getBody().refreshRows(activeRow, 1); + } + + if (oldColumn != activeColumn) { + if (oldRow == activeRow) { + escalator.getBody().refreshRows(oldRow, 1); + } + refreshHeader(); + refreshFooter(); + } + } } diff --git a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java index 6a1f1c3041..d5dd845e92 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java @@ -86,6 +86,9 @@ public abstract class ComplexRenderer implements Renderer { *

* The events that triggers this needs to be returned by the * {@link #getConsumedEvents()} method. + *

+ * Returns boolean telling if the event has been completely handled and + * should not cause any other actions. * * @param cell * Object containing information about the cell the event was @@ -93,9 +96,10 @@ public abstract class ComplexRenderer implements Renderer { * * @param event * The original DOM event + * @return true if event should not be handled by grid */ - public void onBrowserEvent(Cell cell, NativeEvent event) { - // Implement if needed + public boolean onBrowserEvent(Cell cell, NativeEvent event) { + return false; } /** diff --git a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java index 3754c51f18..aa063a34e7 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java @@ -482,7 +482,7 @@ public class MultiSelectionRenderer extends ComplexRenderer { } @Override - public void onBrowserEvent(final Cell cell, final NativeEvent event) { + public boolean onBrowserEvent(final Cell cell, final NativeEvent event) { if (BrowserEvents.TOUCHSTART.equals(event.getType()) || BrowserEvents.MOUSEDOWN.equals(event.getType())) { injectNativeHandler(); @@ -491,6 +491,7 @@ public class MultiSelectionRenderer extends ComplexRenderer { autoScrollHandler.start(logicalRowIndex); event.preventDefault(); event.stopPropagation(); + return true; } else { throw new IllegalStateException("received unexpected event: " + event.getType()); diff --git a/uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java new file mode 100644 index 0000000000..927b941131 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java @@ -0,0 +1,66 @@ +/* + * 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.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class GridKeyboardNavigationTest extends MultiBrowserTest { + + @Override + protected Class getUIClass() { + return GridBasicFeatures.class; + } + + @Test + public void testCellActiveOnClick() { + openTestURL(); + + GridElement grid = getGridElement(); + assertTrue("Body cell 0, 0 is not active on init.", + cellIsActive(grid, 0, 0)); + grid.getCell(5, 2).click(); + assertFalse("Body cell 0, 0 was still active after clicking", + cellIsActive(grid, 0, 0)); + assertTrue("Body cell 5, 2 is not active after clicking", + cellIsActive(grid, 5, 2)); + } + + @Test + public void testCellNotActiveWhenRendererHandlesEvent() { + openTestURL(); + + GridElement grid = getGridElement(); + assertTrue("Body cell 0, 0 is not active on init.", + cellIsActive(grid, 0, 0)); + grid.getHeaderCell(0, 3).click(); + assertTrue("Body cell 0, 0 is not active after click on header.", + cellIsActive(grid, 0, 0)); + } + + private boolean cellIsActive(GridElement grid, int row, int col) { + return grid.getCell(row, col).getAttribute("class") + .contains("-cell-active"); + } + + private GridElement getGridElement() { + return $(GridElement.class).first(); + } +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java index 40dbbeb370..9ee05cb036 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java @@ -58,11 +58,12 @@ public class RowAwareRendererConnector extends AbstractRendererConnector { } @Override - public void onBrowserEvent(Cell cell, NativeEvent event) { + 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; } } -- cgit v1.2.3 From 9c8211611b3b49c877966e6b4248aecb5bf27c27 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 10 Jul 2014 16:54:22 +0300 Subject: Split GridBasicFeaturesTest to sub tests Change-Id: I17f2c9e289cd08f583fcccfbd2852d38afeda180 --- .../tests/components/grid/GridBasicFeatures.java | 544 ------------------ .../components/grid/GridBasicFeaturesTest.java | 620 --------------------- .../grid/basicfeatures/GridBasicFeatures.java | 544 ++++++++++++++++++ .../grid/basicfeatures/GridBasicFeaturesTest.java | 79 +++ .../grid/basicfeatures/GridSelectionTest.java | 119 ++++ .../grid/basicfeatures/GridSortingTest.java | 159 ++++++ .../grid/basicfeatures/GridStructureTest.java | 347 ++++++++++++ 7 files changed, 1248 insertions(+), 1164 deletions(-) delete mode 100644 uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java deleted file mode 100644 index 6e4bafc797..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java +++ /dev/null @@ -1,544 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid; - -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -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.HeightMode; -import com.vaadin.shared.ui.grid.SortDirection; -import com.vaadin.tests.components.AbstractComponentTest; -import com.vaadin.ui.components.grid.ColumnGroup; -import com.vaadin.ui.components.grid.ColumnGroupRow; -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.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 { - - private static final int MANUALLY_FORMATTED_COLUMNS = 4; - public static final int COLUMNS = 11; - 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 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, ""); - - 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(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( - "" + row + ""); - - item.getItemProperty(getColumnProperty(col++)).setValue( - rand.nextInt()); - } - } - - // 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()); - } - - // Add footer values (header values are automatically created) - for (int col = 0; col < COLUMNS; col++) { - grid.getColumn(getColumnProperty(col)).setFooterCaption( - "Footer " + col); - } - - // Set varying column widths - for (int col = 0; col < COLUMNS; col++) { - grid.getColumn("Column" + col).setWidth(100 + col * 50); - } - - grid.addSortOrderChangeListener(new SortOrderChangeListener() { - @Override - public void sortOrderChange(SortOrderChangeEvent event) { - log("Sort order: " + event.getSortOrder()); - } - }); - - grid.setSelectionMode(SelectionMode.NONE); - - createGridActions(); - - createColumnActions(); - - createHeaderActions(); - - createFooterActions(); - - createColumnGroupActions(); - - createRowActions(); - - addHeightActions(); - - return grid; - } - - protected void createGridActions() { - LinkedHashMap primaryStyleNames = new LinkedHashMap(); - 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() { - - @Override - public void execute(Grid grid, String value, Object data) { - grid.setPrimaryStyleName(value); - - } - }, primaryStyleNames.get("v-grid")); - - LinkedHashMap selectionModes = new LinkedHashMap(); - selectionModes.put("single", SelectionMode.SINGLE); - selectionModes.put("multi", SelectionMode.MULTI); - selectionModes.put("none", SelectionMode.NONE); - createSelectAction("Selection mode", "State", selectionModes, "none", - new Command() { - @Override - public void execute(Grid grid, SelectionMode selectionMode, - Object data) { - grid.setSelectionMode(selectionMode); - } - }); - - LinkedHashMap> sortableProperties = new LinkedHashMap>(); - 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>() { - @Override - public void execute(Grid grid, List sortOrder, - Object data) { - grid.setSortOrder(sortOrder); - } - }); - } - - protected void createHeaderActions() { - createCategory("Headers", null); - - createBooleanAction("Visible", "Headers", true, - new Command() { - - @Override - public void execute(Grid grid, Boolean value, Object data) { - grid.setColumnHeadersVisible(value); - } - }); - } - - protected void createFooterActions() { - createCategory("Footers", null); - - createBooleanAction("Visible", "Footers", false, - new Command() { - - @Override - public void execute(Grid grid, Boolean value, Object data) { - grid.setColumnFootersVisible(value); - } - }); - } - - protected void createColumnActions() { - createCategory("Columns", null); - - for (int c = 0; c < COLUMNS; c++) { - createCategory(getColumnProperty(c), "Columns"); - - createBooleanAction("Visible", getColumnProperty(c), true, - new Command() { - - @Override - public void execute(Grid grid, Boolean value, - Object columnIndex) { - Object propertyId = (new ArrayList(grid - .getContainerDatasource() - .getContainerPropertyIds()) - .get((Integer) columnIndex)); - GridColumn column = grid.getColumn(propertyId); - column.setVisible(!column.isVisible()); - } - }, c); - - createClickAction("Remove", getColumnProperty(c), - new Command() { - - @Override - public void execute(Grid grid, String value, Object data) { - grid.getContainerDatasource() - .removeContainerProperty("Column" + data); - } - }, null, c); - - createClickAction("Freeze", getColumnProperty(c), - new Command() { - - @Override - public void execute(Grid grid, String value, Object data) { - grid.setLastFrozenPropertyId("Column" + data); - } - }, null, c); - - createBooleanAction("Sortable", getColumnProperty(c), true, - new Command() { - - @Override - public void execute(Grid grid, Boolean value, - Object columnIndex) { - Object propertyId = (new ArrayList(grid - .getContainerDatasource() - .getContainerPropertyIds()) - .get((Integer) columnIndex)); - GridColumn column = grid.getColumn(propertyId); - column.setSortable(value); - } - }, c); - - createCategory("Column" + c + " Width", getColumnProperty(c)); - - createClickAction("Auto", "Column" + c + " Width", - new Command() { - - @Override - public void execute(Grid grid, Integer value, - Object columnIndex) { - Object propertyId = (new ArrayList(grid - .getContainerDatasource() - .getContainerPropertyIds()) - .get((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() { - - @Override - public void execute(Grid grid, Integer value, - Object columnIndex) { - Object propertyId = (new ArrayList(grid - .getContainerDatasource() - .getContainerPropertyIds()) - .get((Integer) columnIndex)); - GridColumn column = grid.getColumn(propertyId); - column.setWidth(value); - } - }, w, c); - } - } - } - - private static String getColumnProperty(int c) { - return "Column" + c; - } - - protected void createColumnGroupActions() { - createCategory("Column groups", null); - - createClickAction("Add group row", "Column groups", - new Command() { - - @Override - public void execute(Grid grid, String value, Object data) { - final ColumnGroupRow row = grid.addColumnGroupRow(); - columnGroupRows++; - createCategory("Column group row " + columnGroupRows, - "Column groups"); - - createBooleanAction("Header Visible", - "Column group row " + columnGroupRows, true, - new Command() { - - @Override - public void execute(Grid grid, - Boolean value, Object columnIndex) { - row.setHeaderVisible(value); - } - }, row); - - createBooleanAction("Footer Visible", - "Column group row " + columnGroupRows, false, - new Command() { - - @Override - public void execute(Grid grid, - Boolean value, Object columnIndex) { - row.setFooterVisible(value); - } - }, row); - - for (int i = 0; i < COLUMNS; i++) { - final int columnIndex = i; - createClickAction("Group Column " + columnIndex - + " & " + (columnIndex + 1), - "Column group row " + columnGroupRows, - new Command() { - - @Override - public void execute(Grid c, - Integer value, Object data) { - final ColumnGroup group = row - .addGroup( - "Column" + value, - "Column" - + (value + 1)); - - group.setHeaderCaption("Column " - + value + " & " - + (value + 1)); - - group.setFooterCaption("Column " - + value + " & " - + (value + 1)); - } - }, i, row); - } - } - }, null, null); - - } - - protected void createRowActions() { - createCategory("Body rows", null); - - createClickAction("Add first row", "Body rows", - new Command() { - @Override - public void execute(Grid c, String value, Object data) { - Item item = ds.addItemAt(0, new Object()); - for (int i = 0; i < COLUMNS; i++) { - item.getItemProperty(getColumnProperty(i)) - .setValue("newcell: " + i); - } - } - }, null); - - createClickAction("Remove first row", "Body rows", - new Command() { - @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() { - @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) property) - .setValue("modified: " + i); - } - } - } - }, null); - - createClickAction("Modify first row (getContainerProperty)", - "Body rows", new Command() { - @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) property) - .setValue("modified: " - + containerPropertyId); - } - } - } - }, null); - - createBooleanAction("Select first row", "Body rows", false, - new Command() { - @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); - } - } - }); - } - - @SuppressWarnings("boxing") - protected void addHeightActions() { - createCategory("Height by Rows", "Size"); - - createBooleanAction("HeightMode Row", "Size", false, - new Command() { - @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 sizeCommand = new Command() { - @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() { - @Override - public void execute(Grid c, String value, Object data) { - c.setHeightByRows(i); - } - }, null); - } - - @Override - protected Integer getTicketNumber() { - return 12829; - } - - @Override - protected Class getTestClass() { - return Grid.class; - } - -} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java deleted file mode 100644 index a94550721e..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeaturesTest.java +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid; - -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.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.junit.Test; -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 com.vaadin.testbench.TestBenchElement; -import com.vaadin.tests.annotations.TestCategory; -import com.vaadin.tests.tb3.MultiBrowserTest; - -@TestCategory("grid") -public class GridBasicFeaturesTest extends MultiBrowserTest { - - @Test - public void testColumnHeaderCaptions() throws Exception { - openTestURL(); - - // Column headers should be visible - List cells = getGridHeaderRowCells(); - assertEquals(GridBasicFeatures.COLUMNS, cells.size()); - assertEquals("Column0", cells.get(0).getText()); - assertEquals("Column1", cells.get(1).getText()); - assertEquals("Column2", cells.get(2).getText()); - } - - @Test - public void testColumnFooterCaptions() throws Exception { - openTestURL(); - - // footer row should by default be hidden - List cells = getGridFooterRowCells(); - assertEquals(0, cells.size()); - - // Open footer row - selectMenuPath("Component", "Footers", "Visible"); - - // Footers should now be visible - cells = getGridFooterRowCells(); - assertEquals(GridBasicFeatures.COLUMNS, cells.size()); - assertEquals("Footer 0", cells.get(0).getText()); - assertEquals("Footer 1", cells.get(1).getText()); - assertEquals("Footer 2", cells.get(2).getText()); - } - - @Test - public void testColumnGroupHeaders() throws Exception { - openTestURL(); - - // Hide column headers for this test - selectMenuPath("Component", "Headers", "Visible"); - - List cells = getGridHeaderRowCells(); - - // header row should be empty - assertEquals(0, cells.size()); - - // add a group row - selectMenuPath("Component", "Column groups", "Add group row"); - - // Empty group row cells should be present - cells = getGridHeaderRowCells(); - assertEquals(GridBasicFeatures.COLUMNS, cells.size()); - - // Group columns 0 & 1 - selectMenuPath("Component", "Column groups", "Column group row 1", - "Group Column 0 & 1"); - - cells = getGridHeaderRowCells(); - assertEquals("Column 0 & 1", cells.get(0).getText()); - } - - @Test - public void testColumnGroupFooters() throws Exception { - openTestURL(); - - // add a group row - selectMenuPath("Component", "Column groups", "Add group row"); - - // Set footer visible - selectMenuPath("Component", "Column groups", "Column group row 1", - "Footer Visible"); - - // Group columns 0 & 1 - selectMenuPath("Component", "Column groups", "Column group row 1", - "Group Column 0 & 1"); - - List cells = getGridFooterRowCells(); - assertEquals("Column 0 & 1", cells.get(0).getText()); - } - - @Test - public void testGroupingSameColumnsOnRowThrowsException() throws Exception { - openTestURL(); - - // add a group row - selectMenuPath("Component", "Column groups", "Add group row"); - - // Group columns 0 & 1 - selectMenuPath("Component", "Column groups", "Column group row 1", - "Group Column 0 & 1"); - - // Group columns 1 & 2 shoud fail - selectMenuPath("Component", "Column groups", "Column group row 1", - "Group Column 1 & 2"); - - assertTrue(getLogRow(0) - .contains( - "Exception occured, java.lang.IllegalArgumentExceptionColumn Column1 already belongs to another group.")); - } - - @Test - public void testHidingColumn() throws Exception { - openTestURL(); - - // Column 0 should be visible - List cells = getGridHeaderRowCells(); - assertEquals("Column0", cells.get(0).getText()); - - // Hide column 0 - selectMenuPath("Component", "Columns", "Column0", "Visible"); - - // Column 1 should now be the first cell - cells = getGridHeaderRowCells(); - assertEquals("Column1", cells.get(0).getText()); - } - - @Test - public void testRemovingColumn() throws Exception { - openTestURL(); - - // Column 0 should be visible - List cells = getGridHeaderRowCells(); - assertEquals("Column0", cells.get(0).getText()); - - // Hide column 0 - selectMenuPath("Component", "Columns", "Column0", "Remove"); - - // Column 1 should now be the first cell - cells = getGridHeaderRowCells(); - assertEquals("Column1", cells.get(0).getText()); - } - - @Test - public void testDataLoadingAfterRowRemoval() throws Exception { - openTestURL(); - - // Remove columns 2,3,4 - selectMenuPath("Component", "Columns", "Column2", "Remove"); - selectMenuPath("Component", "Columns", "Column3", "Remove"); - selectMenuPath("Component", "Columns", "Column4", "Remove"); - - // Scroll so new data is lazy loaded - scrollGridVerticallyTo(1000); - - // Let lazy loading do its job - sleep(1000); - - // Check that row is loaded - assertThat(getBodyCellByRowAndColumn(11, 0).getText(), not("...")); - } - - @Test - public void testFreezingColumn() throws Exception { - openTestURL(); - - // Freeze column 2 - selectMenuPath("Component", "Columns", "Column2", "Freeze"); - - WebElement cell = getBodyCellByRowAndColumn(0, 0); - assertTrue(cell.getAttribute("class").contains("frozen")); - - cell = getBodyCellByRowAndColumn(0, 1); - assertTrue(cell.getAttribute("class").contains("frozen")); - } - - @Test - public void testInitialColumnWidths() throws Exception { - openTestURL(); - - WebElement cell = getBodyCellByRowAndColumn(0, 0); - assertEquals(100, cell.getSize().getWidth()); - - cell = getBodyCellByRowAndColumn(0, 1); - assertEquals(150, cell.getSize().getWidth()); - - cell = getBodyCellByRowAndColumn(0, 2); - assertEquals(200, cell.getSize().getWidth()); - } - - @Test - public void testColumnWidths() throws Exception { - openTestURL(); - - // Default column width is 100px - WebElement cell = getBodyCellByRowAndColumn(0, 0); - assertEquals(100, cell.getSize().getWidth()); - - // Set first column to be 200px wide - selectMenuPath("Component", "Columns", "Column0", "Column0 Width", - "200px"); - - cell = getBodyCellByRowAndColumn(0, 0); - assertEquals(200, cell.getSize().getWidth()); - - // Set second column to be 150px wide - selectMenuPath("Component", "Columns", "Column1", "Column1 Width", - "150px"); - cell = getBodyCellByRowAndColumn(0, 1); - assertEquals(150, cell.getSize().getWidth()); - - // Set first column to be auto sized (defaults to 100px currently) - selectMenuPath("Component", "Columns", "Column0", "Column0 Width", - "Auto"); - - cell = getBodyCellByRowAndColumn(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)", - getBodyCellByRowAndColumn(0, 0).getText()); - - selectMenuPath("Component", "Body rows", - "Modify first row (getItemProperty)"); - assertEquals("(First) modification with getItemProperty failed", - "modified: 0", getBodyCellByRowAndColumn(0, 0).getText()); - - selectMenuPath("Component", "Body rows", - "Modify first row (getContainerProperty)"); - assertEquals("(Second) modification with getItemProperty failed", - "modified: Column0", getBodyCellByRowAndColumn(0, 0).getText()); - } - - @Test - public void testSelectOnOff() throws Exception { - openTestURL(); - - setSelectionModelMulti(); - - assertFalse("row shouldn't start out as selected", - isSelected(getRow(0))); - toggleFirstRowSelection(); - assertTrue("row should become selected", isSelected(getRow(0))); - toggleFirstRowSelection(); - assertFalse("row shouldn't remain selected", isSelected(getRow(0))); - } - - @Test - public void testSelectOnScrollOffScroll() throws Exception { - openTestURL(); - - setSelectionModelMulti(); - - assertFalse("row shouldn't start out as selected", - isSelected(getRow(0))); - toggleFirstRowSelection(); - assertTrue("row should become selected", isSelected(getRow(0))); - - 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", isSelected(getRow(0))); - } - - @Test - public void testSelectScrollOnScrollOff() throws Exception { - openTestURL(); - - setSelectionModelMulti(); - - assertFalse("row shouldn't start out as selected", - isSelected(getRow(0))); - - 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", isSelected(getRow(0))); - - toggleFirstRowSelection(); - assertFalse("row shouldn't remain selected", isSelected(getRow(0))); - } - - @Test - public void testSelectScrollOnOffScroll() throws Exception { - openTestURL(); - - setSelectionModelMulti(); - - assertFalse("row shouldn't start out as selected", - isSelected(getRow(0))); - - 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", isSelected(getRow(0))); - } - - @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("Column9, DESC"); - - 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 Column9 using descending direction.", - "(" + row + ", 0)", grid.getCell(i, 0).getText()); - } - - // Column 10 is random numbers from Random with seed 13334 - sortBy("Column10, 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 Column10 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("Column7, DESC"); - for (int i = 0; i < 3; ++i) { - assertEquals( - "Grid is not sorted by Column7 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 Column9 using descending direction.", - "(" + row + ", 0)", grid.getCell(i, 0).getText()); - } - - assertEquals("2. Sort order: [Column9 ASCENDING]", getLogRow(2)); - assertEquals("4. Sort order: [Column9 DESCENDING]", 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: [Column10 ASCENDING]", 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 Column10 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 Column7 using descending direction", - "(" + i + ", 0)", - grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText()); - } - - assertEquals("9. Sort order: [Column7 ASCENDING]", getLogRow(3)); - assertEquals("11. Sort order: [Column7 DESCENDING]", getLogRow(1)); - } - - private void sortBy(String column) { - selectMenuPath("Component", "State", "Sort by column", column); - } - - private void toggleFirstRowSelection() { - selectMenuPath("Component", "Body rows", "Select first row"); - } - - @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 TestBenchElement getRow(int i) { - return getGridElement().getRow(i); - } - - private void assertPrimaryStylename(String stylename) { - assertTrue(getGridElement().getAttribute("class").contains(stylename)); - - String tableWrapperStyleName = getTableWrapper().getAttribute("class"); - assertTrue(tableWrapperStyleName.contains(stylename + "-tablewrapper")); - - String hscrollStyleName = getHorizontalScroller().getAttribute("class"); - assertTrue(hscrollStyleName.contains(stylename + "-scroller")); - assertTrue(hscrollStyleName - .contains(stylename + "-scroller-horizontal")); - - String vscrollStyleName = getVerticalScroller().getAttribute("class"); - assertTrue(vscrollStyleName.contains(stylename + "-scroller")); - assertTrue(vscrollStyleName.contains(stylename + "-scroller-vertical")); - } - - private void setSelectionModelMulti() { - selectMenuPath("Component", "State", "Selection mode", "multi"); - } - - private WebElement getBodyCellByRowAndColumn(int row, int column) { - return getGridElement().getCell(row, column); - } - - private void selectSubMenu(String menuCaption) { - selectMenu(menuCaption); - new Actions(getDriver()).moveByOffset(100, 0).build().perform(); - } - - private void selectMenu(String menuCaption) { - getDriver().findElement( - By.xpath("//span[text() = '" + menuCaption + "']")).click(); - } - - private void selectMenuPath(String... menuCaptions) { - selectMenu(menuCaptions[0]); - for (int i = 1; i < menuCaptions.length; i++) { - selectSubMenu(menuCaptions[i]); - } - } - - private WebElement getVerticalScroller() { - return getGridElement().findElement(By.xpath("./div[1]")); - } - - private WebElement getHorizontalScroller() { - return getGridElement().findElement(By.xpath("./div[2]")); - } - - private WebElement getTableWrapper() { - return getGridElement().findElement(By.xpath("./div[3]")); - } - - private GridElement getGridElement() { - return $(GridElement.class).id("testComponent"); - } - - private List getGridHeaderRowCells() { - List headerCells = new ArrayList(); - for (int i = 0; i < getGridElement().getHeaderCount(); ++i) { - headerCells.addAll(getGridElement().getHeaderCells(i)); - } - return headerCells; - } - - private List getGridFooterRowCells() { - List footerCells = new ArrayList(); - for (int i = 0; i < getGridElement().getFooterCount(); ++i) { - footerCells.addAll(getGridElement().getFooterCells(i)); - } - return footerCells; - } - - private void scrollGridVerticallyTo(double px) { - executeScript("arguments[0].scrollTop = " + px, - getGridVerticalScrollbar()); - } - - private Object executeScript(String script, WebElement element) { - @SuppressWarnings("hiding") - 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()); - } - } - - private 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/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java new file mode 100644 index 0000000000..316d7116e3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -0,0 +1,544 @@ +/* + * 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.ArrayList; +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.HeightMode; +import com.vaadin.shared.ui.grid.SortDirection; +import com.vaadin.tests.components.AbstractComponentTest; +import com.vaadin.ui.components.grid.ColumnGroup; +import com.vaadin.ui.components.grid.ColumnGroupRow; +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.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 { + + private static final int MANUALLY_FORMATTED_COLUMNS = 4; + public static final int COLUMNS = 11; + 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 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, ""); + + 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(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( + "" + row + ""); + + item.getItemProperty(getColumnProperty(col++)).setValue( + rand.nextInt()); + } + } + + // 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()); + } + + // Add footer values (header values are automatically created) + for (int col = 0; col < COLUMNS; col++) { + grid.getColumn(getColumnProperty(col)).setFooterCaption( + "Footer " + col); + } + + // Set varying column widths + for (int col = 0; col < COLUMNS; col++) { + grid.getColumn("Column" + col).setWidth(100 + col * 50); + } + + grid.addSortOrderChangeListener(new SortOrderChangeListener() { + @Override + public void sortOrderChange(SortOrderChangeEvent event) { + log("Sort order: " + event.getSortOrder()); + } + }); + + grid.setSelectionMode(SelectionMode.NONE); + + createGridActions(); + + createColumnActions(); + + createHeaderActions(); + + createFooterActions(); + + createColumnGroupActions(); + + createRowActions(); + + addHeightActions(); + + return grid; + } + + protected void createGridActions() { + LinkedHashMap primaryStyleNames = new LinkedHashMap(); + 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() { + + @Override + public void execute(Grid grid, String value, Object data) { + grid.setPrimaryStyleName(value); + + } + }, primaryStyleNames.get("v-grid")); + + LinkedHashMap selectionModes = new LinkedHashMap(); + selectionModes.put("single", SelectionMode.SINGLE); + selectionModes.put("multi", SelectionMode.MULTI); + selectionModes.put("none", SelectionMode.NONE); + createSelectAction("Selection mode", "State", selectionModes, "none", + new Command() { + @Override + public void execute(Grid grid, SelectionMode selectionMode, + Object data) { + grid.setSelectionMode(selectionMode); + } + }); + + LinkedHashMap> sortableProperties = new LinkedHashMap>(); + 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>() { + @Override + public void execute(Grid grid, List sortOrder, + Object data) { + grid.setSortOrder(sortOrder); + } + }); + } + + protected void createHeaderActions() { + createCategory("Headers", null); + + createBooleanAction("Visible", "Headers", true, + new Command() { + + @Override + public void execute(Grid grid, Boolean value, Object data) { + grid.setColumnHeadersVisible(value); + } + }); + } + + protected void createFooterActions() { + createCategory("Footers", null); + + createBooleanAction("Visible", "Footers", false, + new Command() { + + @Override + public void execute(Grid grid, Boolean value, Object data) { + grid.setColumnFootersVisible(value); + } + }); + } + + protected void createColumnActions() { + createCategory("Columns", null); + + for (int c = 0; c < COLUMNS; c++) { + createCategory(getColumnProperty(c), "Columns"); + + createBooleanAction("Visible", getColumnProperty(c), true, + new Command() { + + @Override + public void execute(Grid grid, Boolean value, + Object columnIndex) { + Object propertyId = (new ArrayList(grid + .getContainerDatasource() + .getContainerPropertyIds()) + .get((Integer) columnIndex)); + GridColumn column = grid.getColumn(propertyId); + column.setVisible(!column.isVisible()); + } + }, c); + + createClickAction("Remove", getColumnProperty(c), + new Command() { + + @Override + public void execute(Grid grid, String value, Object data) { + grid.getContainerDatasource() + .removeContainerProperty("Column" + data); + } + }, null, c); + + createClickAction("Freeze", getColumnProperty(c), + new Command() { + + @Override + public void execute(Grid grid, String value, Object data) { + grid.setLastFrozenPropertyId("Column" + data); + } + }, null, c); + + createBooleanAction("Sortable", getColumnProperty(c), true, + new Command() { + + @Override + public void execute(Grid grid, Boolean value, + Object columnIndex) { + Object propertyId = (new ArrayList(grid + .getContainerDatasource() + .getContainerPropertyIds()) + .get((Integer) columnIndex)); + GridColumn column = grid.getColumn(propertyId); + column.setSortable(value); + } + }, c); + + createCategory("Column" + c + " Width", getColumnProperty(c)); + + createClickAction("Auto", "Column" + c + " Width", + new Command() { + + @Override + public void execute(Grid grid, Integer value, + Object columnIndex) { + Object propertyId = (new ArrayList(grid + .getContainerDatasource() + .getContainerPropertyIds()) + .get((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() { + + @Override + public void execute(Grid grid, Integer value, + Object columnIndex) { + Object propertyId = (new ArrayList(grid + .getContainerDatasource() + .getContainerPropertyIds()) + .get((Integer) columnIndex)); + GridColumn column = grid.getColumn(propertyId); + column.setWidth(value); + } + }, w, c); + } + } + } + + private static String getColumnProperty(int c) { + return "Column" + c; + } + + protected void createColumnGroupActions() { + createCategory("Column groups", null); + + createClickAction("Add group row", "Column groups", + new Command() { + + @Override + public void execute(Grid grid, String value, Object data) { + final ColumnGroupRow row = grid.addColumnGroupRow(); + columnGroupRows++; + createCategory("Column group row " + columnGroupRows, + "Column groups"); + + createBooleanAction("Header Visible", + "Column group row " + columnGroupRows, true, + new Command() { + + @Override + public void execute(Grid grid, + Boolean value, Object columnIndex) { + row.setHeaderVisible(value); + } + }, row); + + createBooleanAction("Footer Visible", + "Column group row " + columnGroupRows, false, + new Command() { + + @Override + public void execute(Grid grid, + Boolean value, Object columnIndex) { + row.setFooterVisible(value); + } + }, row); + + for (int i = 0; i < COLUMNS; i++) { + final int columnIndex = i; + createClickAction("Group Column " + columnIndex + + " & " + (columnIndex + 1), + "Column group row " + columnGroupRows, + new Command() { + + @Override + public void execute(Grid c, + Integer value, Object data) { + final ColumnGroup group = row + .addGroup( + "Column" + value, + "Column" + + (value + 1)); + + group.setHeaderCaption("Column " + + value + " & " + + (value + 1)); + + group.setFooterCaption("Column " + + value + " & " + + (value + 1)); + } + }, i, row); + } + } + }, null, null); + + } + + protected void createRowActions() { + createCategory("Body rows", null); + + createClickAction("Add first row", "Body rows", + new Command() { + @Override + public void execute(Grid c, String value, Object data) { + Item item = ds.addItemAt(0, new Object()); + for (int i = 0; i < COLUMNS; i++) { + item.getItemProperty(getColumnProperty(i)) + .setValue("newcell: " + i); + } + } + }, null); + + createClickAction("Remove first row", "Body rows", + new Command() { + @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() { + @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) property) + .setValue("modified: " + i); + } + } + } + }, null); + + createClickAction("Modify first row (getContainerProperty)", + "Body rows", new Command() { + @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) property) + .setValue("modified: " + + containerPropertyId); + } + } + } + }, null); + + createBooleanAction("Select first row", "Body rows", false, + new Command() { + @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); + } + } + }); + } + + @SuppressWarnings("boxing") + protected void addHeightActions() { + createCategory("Height by Rows", "Size"); + + createBooleanAction("HeightMode Row", "Size", false, + new Command() { + @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 sizeCommand = new Command() { + @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() { + @Override + public void execute(Grid c, String value, Object data) { + c.setHeightByRows(i); + } + }, null); + } + + @Override + protected Integer getTicketNumber() { + return 12829; + } + + @Override + protected Class 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..3651a0c919 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.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.basicfeatures; + +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 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 Class getUIClass() { + return GridBasicFeatures.class; + } + + private void selectSubMenu(String menuCaption) { + selectMenu(menuCaption); + new Actions(getDriver()).moveByOffset(100, 0).build().perform(); + } + + private 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 $(GridElement.class).id("testComponent"); + } + + protected void scrollGridVerticallyTo(double px) { + executeScript("arguments[0].scrollTop = " + px, + getGridVerticalScrollbar()); + } + + 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()); + } + } + + private 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/GridSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.java new file mode 100644 index 0000000000..e18dc1faa4 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.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 static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.vaadin.testbench.TestBenchElement; +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", + isSelected(getRow(0))); + toggleFirstRowSelection(); + assertTrue("row should become selected", isSelected(getRow(0))); + toggleFirstRowSelection(); + assertFalse("row shouldn't remain selected", isSelected(getRow(0))); + } + + @Test + public void testSelectOnScrollOffScroll() throws Exception { + openTestURL(); + + setSelectionModelMulti(); + + assertFalse("row shouldn't start out as selected", + isSelected(getRow(0))); + toggleFirstRowSelection(); + assertTrue("row should become selected", isSelected(getRow(0))); + + 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", isSelected(getRow(0))); + } + + @Test + public void testSelectScrollOnScrollOff() throws Exception { + openTestURL(); + + setSelectionModelMulti(); + + assertFalse("row shouldn't start out as selected", + isSelected(getRow(0))); + + 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", isSelected(getRow(0))); + + toggleFirstRowSelection(); + assertFalse("row shouldn't remain selected", isSelected(getRow(0))); + } + + @Test + public void testSelectScrollOnOffScroll() throws Exception { + openTestURL(); + + setSelectionModelMulti(); + + assertFalse("row shouldn't start out as selected", + isSelected(getRow(0))); + + 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", isSelected(getRow(0))); + } + + private void setSelectionModelMulti() { + selectMenuPath("Component", "State", "Selection mode", "multi"); + } + + @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 TestBenchElement getRow(int i) { + return getGridElement().getRow(i); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java new file mode 100644 index 0000000000..820070f933 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java @@ -0,0 +1,159 @@ +/* + * 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.io.IOException; + +import org.junit.Test; + +import com.vaadin.tests.components.grid.GridElement; + +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("Column9, DESC"); + + 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 Column9 using descending direction.", + "(" + row + ", 0)", grid.getCell(i, 0).getText()); + } + + // Column 10 is random numbers from Random with seed 13334 + sortBy("Column10, 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 Column10 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("Column7, DESC"); + for (int i = 0; i < 3; ++i) { + assertEquals( + "Grid is not sorted by Column7 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 Column9 using descending direction.", + "(" + row + ", 0)", grid.getCell(i, 0).getText()); + } + + assertEquals("2. Sort order: [Column9 ASCENDING]", getLogRow(2)); + assertEquals("4. Sort order: [Column9 DESCENDING]", 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: [Column10 ASCENDING]", 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 Column10 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 Column7 using descending direction", + "(" + i + ", 0)", + grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText()); + } + + assertEquals("9. Sort order: [Column7 ASCENDING]", getLogRow(3)); + assertEquals("11. Sort order: [Column7 DESCENDING]", getLogRow(1)); + } + + private void sortBy(String column) { + selectMenuPath("Component", "State", "Sort by column", column); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java new file mode 100644 index 0000000000..17438fd4bb --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java @@ -0,0 +1,347 @@ +/* + * 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.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +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.GridBasicFeatures; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; + +public class GridStructureTest extends GridBasicFeaturesTest { + + @Test + public void testColumnHeaderCaptions() throws Exception { + openTestURL(); + + // Column headers should be visible + List cells = getGridHeaderRowCells(); + assertEquals(GridBasicFeatures.COLUMNS, cells.size()); + assertEquals("Column0", cells.get(0).getText()); + assertEquals("Column1", cells.get(1).getText()); + assertEquals("Column2", cells.get(2).getText()); + } + + @Test + public void testColumnFooterCaptions() throws Exception { + openTestURL(); + + // footer row should by default be hidden + List cells = getGridFooterRowCells(); + assertEquals(0, cells.size()); + + // Open footer row + selectMenuPath("Component", "Footers", "Visible"); + + // Footers should now be visible + cells = getGridFooterRowCells(); + assertEquals(GridBasicFeatures.COLUMNS, cells.size()); + assertEquals("Footer 0", cells.get(0).getText()); + assertEquals("Footer 1", cells.get(1).getText()); + assertEquals("Footer 2", cells.get(2).getText()); + } + + @Test + public void testColumnGroupHeaders() throws Exception { + openTestURL(); + + // Hide column headers for this test + selectMenuPath("Component", "Headers", "Visible"); + + List cells = getGridHeaderRowCells(); + + // header row should be empty + assertEquals(0, cells.size()); + + // add a group row + selectMenuPath("Component", "Column groups", "Add group row"); + + // Empty group row cells should be present + cells = getGridHeaderRowCells(); + assertEquals(GridBasicFeatures.COLUMNS, cells.size()); + + // Group columns 0 & 1 + selectMenuPath("Component", "Column groups", "Column group row 1", + "Group Column 0 & 1"); + + cells = getGridHeaderRowCells(); + assertEquals("Column 0 & 1", cells.get(0).getText()); + } + + @Test + public void testColumnGroupFooters() throws Exception { + openTestURL(); + + // add a group row + selectMenuPath("Component", "Column groups", "Add group row"); + + // Set footer visible + selectMenuPath("Component", "Column groups", "Column group row 1", + "Footer Visible"); + + // Group columns 0 & 1 + selectMenuPath("Component", "Column groups", "Column group row 1", + "Group Column 0 & 1"); + + List cells = getGridFooterRowCells(); + assertEquals("Column 0 & 1", cells.get(0).getText()); + } + + @Test + public void testGroupingSameColumnsOnRowThrowsException() throws Exception { + openTestURL(); + + // add a group row + selectMenuPath("Component", "Column groups", "Add group row"); + + // Group columns 0 & 1 + selectMenuPath("Component", "Column groups", "Column group row 1", + "Group Column 0 & 1"); + + // Group columns 1 & 2 shoud fail + selectMenuPath("Component", "Column groups", "Column group row 1", + "Group Column 1 & 2"); + + assertTrue(getLogRow(0) + .contains( + "Exception occured, java.lang.IllegalArgumentExceptionColumn Column1 already belongs to another group.")); + } + + @Test + public void testHidingColumn() throws Exception { + openTestURL(); + + // Column 0 should be visible + List cells = getGridHeaderRowCells(); + assertEquals("Column0", cells.get(0).getText()); + + // Hide column 0 + selectMenuPath("Component", "Columns", "Column0", "Visible"); + + // Column 1 should now be the first cell + cells = getGridHeaderRowCells(); + assertEquals("Column1", cells.get(0).getText()); + } + + @Test + public void testRemovingColumn() throws Exception { + openTestURL(); + + // Column 0 should be visible + List cells = getGridHeaderRowCells(); + assertEquals("Column0", cells.get(0).getText()); + + // Hide column 0 + selectMenuPath("Component", "Columns", "Column0", "Remove"); + + // Column 1 should now be the first cell + cells = getGridHeaderRowCells(); + assertEquals("Column1", cells.get(0).getText()); + } + + @Test + public void testDataLoadingAfterRowRemoval() throws Exception { + openTestURL(); + + // Remove columns 2,3,4 + selectMenuPath("Component", "Columns", "Column2", "Remove"); + selectMenuPath("Component", "Columns", "Column3", "Remove"); + selectMenuPath("Component", "Columns", "Column4", "Remove"); + + // Scroll so new data is lazy loaded + scrollGridVerticallyTo(1000); + + // Let lazy loading do its job + sleep(1000); + + // Check that row is loaded + assertThat(getBodyCellByRowAndColumn(11, 0).getText(), not("...")); + } + + @Test + public void testFreezingColumn() throws Exception { + openTestURL(); + + // Freeze column 2 + selectMenuPath("Component", "Columns", "Column2", "Freeze"); + + WebElement cell = getBodyCellByRowAndColumn(0, 0); + assertTrue(cell.getAttribute("class").contains("frozen")); + + cell = getBodyCellByRowAndColumn(0, 1); + assertTrue(cell.getAttribute("class").contains("frozen")); + } + + @Test + public void testInitialColumnWidths() throws Exception { + openTestURL(); + + WebElement cell = getBodyCellByRowAndColumn(0, 0); + assertEquals(100, cell.getSize().getWidth()); + + cell = getBodyCellByRowAndColumn(0, 1); + assertEquals(150, cell.getSize().getWidth()); + + cell = getBodyCellByRowAndColumn(0, 2); + assertEquals(200, cell.getSize().getWidth()); + } + + @Test + public void testColumnWidths() throws Exception { + openTestURL(); + + // Default column width is 100px + WebElement cell = getBodyCellByRowAndColumn(0, 0); + assertEquals(100, cell.getSize().getWidth()); + + // Set first column to be 200px wide + selectMenuPath("Component", "Columns", "Column0", "Column0 Width", + "200px"); + + cell = getBodyCellByRowAndColumn(0, 0); + assertEquals(200, cell.getSize().getWidth()); + + // Set second column to be 150px wide + selectMenuPath("Component", "Columns", "Column1", "Column1 Width", + "150px"); + cell = getBodyCellByRowAndColumn(0, 1); + assertEquals(150, cell.getSize().getWidth()); + + // Set first column to be auto sized (defaults to 100px currently) + selectMenuPath("Component", "Columns", "Column0", "Column0 Width", + "Auto"); + + cell = getBodyCellByRowAndColumn(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)", + getBodyCellByRowAndColumn(0, 0).getText()); + + selectMenuPath("Component", "Body rows", + "Modify first row (getItemProperty)"); + assertEquals("(First) modification with getItemProperty failed", + "modified: 0", getBodyCellByRowAndColumn(0, 0).getText()); + + selectMenuPath("Component", "Body rows", + "Modify first row (getContainerProperty)"); + assertEquals("(Second) modification with getItemProperty failed", + "modified: Column0", getBodyCellByRowAndColumn(0, 0).getText()); + } + + private void assertPrimaryStylename(String stylename) { + assertTrue(getGridElement().getAttribute("class").contains(stylename)); + + String tableWrapperStyleName = getTableWrapper().getAttribute("class"); + assertTrue(tableWrapperStyleName.contains(stylename + "-tablewrapper")); + + String hscrollStyleName = getHorizontalScroller().getAttribute("class"); + assertTrue(hscrollStyleName.contains(stylename + "-scroller")); + assertTrue(hscrollStyleName + .contains(stylename + "-scroller-horizontal")); + + String vscrollStyleName = getVerticalScroller().getAttribute("class"); + assertTrue(vscrollStyleName.contains(stylename + "-scroller")); + assertTrue(vscrollStyleName.contains(stylename + "-scroller-vertical")); + } + + private WebElement getBodyCellByRowAndColumn(int row, int column) { + return getGridElement().getCell(row, column); + } + + private WebElement getVerticalScroller() { + return getGridElement().findElement(By.xpath("./div[1]")); + } + + private WebElement getHorizontalScroller() { + return getGridElement().findElement(By.xpath("./div[2]")); + } + + private WebElement getTableWrapper() { + return getGridElement().findElement(By.xpath("./div[3]")); + } + + private List getGridHeaderRowCells() { + List headerCells = new ArrayList(); + for (int i = 0; i < getGridElement().getHeaderCount(); ++i) { + headerCells.addAll(getGridElement().getHeaderCells(i)); + } + return headerCells; + } + + private List getGridFooterRowCells() { + List footerCells = new ArrayList(); + for (int i = 0; i < getGridElement().getFooterCount(); ++i) { + footerCells.addAll(getGridElement().getFooterCells(i)); + } + return footerCells; + } +} -- cgit v1.2.3 From 44093bb40c6759e02bb7df3a27f649725e2f145d Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 15 Jul 2014 14:36:26 +0300 Subject: Refactor GridKeyboardNavigationTest GridKeyboardNavigationTest is now a subclass of GridBasicFeaturesTest. Change-Id: Ibb169526a035fb77a66024a5170996d9a0607b02 --- .../grid/GridKeyboardNavigationTest.java | 66 ---------------------- .../basicfeatures/GridKeyboardNavigationTest.java | 57 +++++++++++++++++++ 2 files changed, 57 insertions(+), 66 deletions(-) delete mode 100644 uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java deleted file mode 100644 index 927b941131..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/GridKeyboardNavigationTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import com.vaadin.tests.tb3.MultiBrowserTest; - -public class GridKeyboardNavigationTest extends MultiBrowserTest { - - @Override - protected Class getUIClass() { - return GridBasicFeatures.class; - } - - @Test - public void testCellActiveOnClick() { - openTestURL(); - - GridElement grid = getGridElement(); - assertTrue("Body cell 0, 0 is not active on init.", - cellIsActive(grid, 0, 0)); - grid.getCell(5, 2).click(); - assertFalse("Body cell 0, 0 was still active after clicking", - cellIsActive(grid, 0, 0)); - assertTrue("Body cell 5, 2 is not active after clicking", - cellIsActive(grid, 5, 2)); - } - - @Test - public void testCellNotActiveWhenRendererHandlesEvent() { - openTestURL(); - - GridElement grid = getGridElement(); - assertTrue("Body cell 0, 0 is not active on init.", - cellIsActive(grid, 0, 0)); - grid.getHeaderCell(0, 3).click(); - assertTrue("Body cell 0, 0 is not active after click on header.", - cellIsActive(grid, 0, 0)); - } - - private boolean cellIsActive(GridElement grid, int row, int col) { - return grid.getCell(row, col).getAttribute("class") - .contains("-cell-active"); - } - - private GridElement getGridElement() { - return $(GridElement.class).first(); - } -} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java new file mode 100644 index 0000000000..94a25aa321 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java @@ -0,0 +1,57 @@ +/* + * 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 org.junit.Test; + +import com.vaadin.tests.components.grid.GridElement; + +public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { + + @Test + public void testCellActiveOnClick() { + openTestURL(); + + GridElement grid = getGridElement(); + assertTrue("Body cell 0, 0 is not active on init.", + cellIsActive(grid, 0, 0)); + grid.getCell(5, 2).click(); + assertFalse("Body cell 0, 0 was still active after clicking", + cellIsActive(grid, 0, 0)); + assertTrue("Body cell 5, 2 is not active after clicking", + cellIsActive(grid, 5, 2)); + } + + @Test + public void testCellNotActiveWhenRendererHandlesEvent() { + openTestURL(); + + GridElement grid = getGridElement(); + assertTrue("Body cell 0, 0 is not active on init.", + cellIsActive(grid, 0, 0)); + grid.getHeaderCell(0, 3).click(); + assertTrue("Body cell 0, 0 is not active after click on header.", + cellIsActive(grid, 0, 0)); + } + + private boolean cellIsActive(GridElement grid, int row, int col) { + return grid.getCell(row, col).getAttribute("class") + .contains("-cell-active"); + } +} -- cgit v1.2.3 From 8c91be9e2fe478038aa1bf327c9e88d5a040fc77 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 14 Jul 2014 18:50:35 +0300 Subject: Add GridRowElement and GridCellElement (#13334) Change-Id: Ia0fbc8e0a54089f826659969fa281ec8a79b6d87 --- .../vaadin/tests/components/grid/GridElement.java | 65 +++++++++++++++++----- .../basicfeatures/GridKeyboardNavigationTest.java | 23 +++----- 2 files changed, 60 insertions(+), 28 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridElement.java b/uitest/src/com/vaadin/tests/components/grid/GridElement.java index 091c9db1ce..5027c603d9 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridElement.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridElement.java @@ -15,6 +15,7 @@ */ package com.vaadin.tests.components.grid; +import java.util.ArrayList; import java.util.List; import org.openqa.selenium.NoSuchElementException; @@ -22,6 +23,7 @@ import org.openqa.selenium.NoSuchElementException; 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; /** @@ -33,6 +35,30 @@ import com.vaadin.testbench.elements.ServerClass; @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"; + + public boolean isActive() { + return getAttribute("class").contains(ACTIVE_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 * @@ -56,9 +82,10 @@ public class GridElement extends AbstractComponentElement { * Column index * @return Cell element with given indices. */ - public TestBenchElement getCell(int rowIndex, int colIndex) { + public GridCellElement getCell(int rowIndex, int colIndex) { scrollToRow(rowIndex); - return getSubPart("#cell[" + rowIndex + "][" + colIndex + "]"); + return getSubPart("#cell[" + rowIndex + "][" + colIndex + "]").wrap( + GridCellElement.class); } /** @@ -68,9 +95,9 @@ public class GridElement extends AbstractComponentElement { * Row index * @return Row element with given index. */ - public TestBenchElement getRow(int index) { + public GridRowElement getRow(int index) { scrollToRow(index); - return getSubPart("#cell[" + index + "]"); + return getSubPart("#cell[" + index + "]").wrap(GridRowElement.class); } /** @@ -82,8 +109,9 @@ public class GridElement extends AbstractComponentElement { * Column index * @return Header cell element with given indices. */ - public TestBenchElement getHeaderCell(int rowIndex, int colIndex) { - return getSubPart("#header[" + rowIndex + "][" + colIndex + "]"); + public GridCellElement getHeaderCell(int rowIndex, int colIndex) { + return getSubPart("#header[" + rowIndex + "][" + colIndex + "]").wrap( + GridCellElement.class); } /** @@ -95,8 +123,9 @@ public class GridElement extends AbstractComponentElement { * Column index * @return Footer cell element with given indices. */ - public TestBenchElement getFooterCell(int rowIndex, int colIndex) { - return getSubPart("#footer[" + rowIndex + "][" + colIndex + "]"); + public GridCellElement getFooterCell(int rowIndex, int colIndex) { + return getSubPart("#footer[" + rowIndex + "][" + colIndex + "]").wrap( + GridCellElement.class); } /** @@ -106,10 +135,14 @@ public class GridElement extends AbstractComponentElement { * Row index * @return Header cell elements on given row. */ - public List getHeaderCells(int rowIndex) { - return TestBenchElement.wrapElements( + public List getHeaderCells(int rowIndex) { + List headers = new ArrayList(); + for (TestBenchElement e : TestBenchElement.wrapElements( getSubPart("#header[" + rowIndex + "]").findElements( - By.xpath("./th")), getTestBenchCommandExecutor()); + By.xpath("./th")), getCommandExecutor())) { + headers.add(e.wrap(GridCellElement.class)); + } + return headers; } /** @@ -119,10 +152,14 @@ public class GridElement extends AbstractComponentElement { * Row index * @return Header cell elements on given row. */ - public List getFooterCells(int rowIndex) { - return TestBenchElement.wrapElements( + public List getFooterCells(int rowIndex) { + List footers = new ArrayList(); + for (TestBenchElement e : TestBenchElement.wrapElements( getSubPart("#footer[" + rowIndex + "]").findElements( - By.xpath("./td")), getTestBenchCommandExecutor()); + By.xpath("./td")), getCommandExecutor())) { + footers.add(e.wrap(GridCellElement.class)); + } + return footers; } /** diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java index 94a25aa321..a297187b62 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java @@ -29,13 +29,13 @@ public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { openTestURL(); GridElement grid = getGridElement(); - assertTrue("Body cell 0, 0 is not active on init.", - cellIsActive(grid, 0, 0)); + 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", - cellIsActive(grid, 0, 0)); + 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", - cellIsActive(grid, 5, 2)); + grid.getCell(5, 2).isActive()); } @Test @@ -43,15 +43,10 @@ public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { openTestURL(); GridElement grid = getGridElement(); - assertTrue("Body cell 0, 0 is not active on init.", - cellIsActive(grid, 0, 0)); + assertTrue("Body cell 0, 0 is not active on init.", grid.getCell(0, 0) + .isActive()); grid.getHeaderCell(0, 3).click(); - assertTrue("Body cell 0, 0 is not active after click on header.", - cellIsActive(grid, 0, 0)); - } - - private boolean cellIsActive(GridElement grid, int row, int col) { - return grid.getCell(row, col).getAttribute("class") - .contains("-cell-active"); + assertTrue("Body cell 0, 0 is not active after click on header.", grid + .getCell(0, 0).isActive()); } } -- cgit v1.2.3 From 59cdaeddf36f91b0e08464d7cd2beb3dd110445f Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Thu, 10 Jul 2014 19:28:14 +0300 Subject: Generate type data for AbstractRendererConnector.decode (#13334) The presentation type parameter is stored so that decode works without implementers having to implement a getType method. Change-Id: Ia2b9f977f2bf6ed006379cda5eeb61674dd92ee0 --- .../ConnectorBundleLoaderFactory.java | 20 ++++- .../widgetsetutils/metadata/ConnectorBundle.java | 20 +++++ .../metadata/RendererInitVisitor.java | 63 -------------- .../widgetsetutils/metadata/RendererVisitor.java | 99 ++++++++++++++++++++++ .../com/vaadin/client/metadata/TypeDataStore.java | 11 +++ .../grid/renderers/AbstractRendererConnector.java | 20 +++-- .../ui/grid/renderers/TextRendererConnector.java | 5 -- .../renderers/UnsafeHtmlRendererConnector.java | 5 -- .../client/grid/IntArrayRendererConnector.java | 5 -- .../client/grid/RowAwareRendererConnector.java | 5 -- 10 files changed, 163 insertions(+), 90 deletions(-) delete mode 100644 client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererInitVisitor.java create mode 100644 client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererVisitor.java (limited to 'uitest/src') diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java index e02317be78..ab930310aa 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java @@ -61,7 +61,7 @@ import com.vaadin.server.widgetsetutils.metadata.ConnectorInitVisitor; import com.vaadin.server.widgetsetutils.metadata.GeneratedSerializer; import com.vaadin.server.widgetsetutils.metadata.OnStateChangeVisitor; import com.vaadin.server.widgetsetutils.metadata.Property; -import com.vaadin.server.widgetsetutils.metadata.RendererInitVisitor; +import com.vaadin.server.widgetsetutils.metadata.RendererVisitor; import com.vaadin.server.widgetsetutils.metadata.ServerRpcVisitor; import com.vaadin.server.widgetsetutils.metadata.StateInitVisitor; import com.vaadin.server.widgetsetutils.metadata.TypeVisitor; @@ -504,6 +504,7 @@ public class ConnectorBundleLoaderFactory extends Generator { // this after the JS property data has been initialized writePropertyTypes(logger, w, bundle); writeSerializers(logger, w, bundle); + writePresentationTypes(w, bundle); writeDelegateToWidget(logger, w, bundle); writeOnStateChangeHandlers(logger, w, bundle); } @@ -680,6 +681,21 @@ public class ConnectorBundleLoaderFactory extends Generator { } } + private void writePresentationTypes(SplittingSourceWriter w, + ConnectorBundle bundle) { + Map presentationTypes = bundle + .getPresentationTypes(); + for (Entry entry : presentationTypes.entrySet()) { + + w.print("store.setPresentationType("); + writeClassLiteral(w, entry.getKey()); + w.print(", "); + writeClassLiteral(w, entry.getValue()); + w.println(");"); + w.splitIfNeeded(); + } + } + private void writePropertyTypes(TreeLogger logger, SplittingSourceWriter w, ConnectorBundle bundle) { Set properties = bundle.getNeedsProperty(); @@ -1236,7 +1252,7 @@ public class ConnectorBundleLoaderFactory extends Generator { throws NotFoundException { List visitors = Arrays. asList( new ConnectorInitVisitor(), new StateInitVisitor(), - new WidgetInitVisitor(), new RendererInitVisitor(), + new WidgetInitVisitor(), new RendererVisitor(), new ClientRpcVisitor(), new ServerRpcVisitor(), new OnStateChangeVisitor()); for (TypeVisitor typeVisitor : visitors) { diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java index 463bf00027..80456cdf10 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java @@ -59,6 +59,7 @@ public class ConnectorBundle { private final Set hasSerializeSupport = new HashSet(); private final Set needsSerializeSupport = new HashSet(); private final Map serializers = new HashMap(); + private final Map presentationTypes = new HashMap(); private final Set needsSuperClass = new HashSet(); private final Set needsGwtConstructor = new HashSet(); @@ -306,6 +307,25 @@ public class ConnectorBundle { return Collections.unmodifiableMap(serializers); } + public void setPresentationType(JClassType type, JType presentationType) { + if (!hasPresentationType(type)) { + presentationTypes.put(type, presentationType); + } + } + + private boolean hasPresentationType(JClassType type) { + if (presentationTypes.containsKey(type)) { + return true; + } else { + return previousBundle != null + && previousBundle.hasPresentationType(type); + } + } + + public Map getPresentationTypes() { + return Collections.unmodifiableMap(presentationTypes); + } + private void setNeedsSuperclass(JClassType typeAsClass) { if (!isNeedsSuperClass(typeAsClass)) { needsSuperClass.add(typeAsClass); diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererInitVisitor.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererInitVisitor.java deleted file mode 100644 index ec68f05b8f..0000000000 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererInitVisitor.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.server.widgetsetutils.metadata; - -import com.google.gwt.core.ext.TreeLogger; -import com.google.gwt.core.ext.UnableToCompleteException; -import com.google.gwt.core.ext.typeinfo.JClassType; -import com.google.gwt.core.ext.typeinfo.JMethod; -import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; - -/** - * Generates type data for renderer connectors. Specifically, stores the return - * type of the overridden {@link AbstractRendererConnector#getRenderer() - * getRenderer} method to enable automatic creation of an instance of the proper - * renderer type. - * - * @see WidgetInitVisitor - * - * @since - * @author Vaadin Ltd - */ -public class RendererInitVisitor extends TypeVisitor { - - @Override - public void visitConnector(TreeLogger logger, JClassType type, - ConnectorBundle bundle) throws UnableToCompleteException { - - if (ConnectorBundle.isConnectedRendererConnector(type)) { - - // The class in which createRenderer is implemented - JClassType createRendererClass = ConnectorBundle - .findInheritedMethod(type, "createRenderer") - .getEnclosingType(); - - JMethod getRenderer = ConnectorBundle.findInheritedMethod(type, - "getRenderer"); - JClassType rendererType = getRenderer.getReturnType().isClass(); - - // Needs GWT constructor if createRenderer is not overridden - if (createRendererClass.getQualifiedSourceName().equals( - AbstractRendererConnector.class.getCanonicalName())) { - - bundle.setNeedsGwtConstructor(rendererType); - - // Also needs renderer type to find the right GWT constructor - bundle.setNeedsReturnType(type, getRenderer); - } - } - } -} diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererVisitor.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererVisitor.java new file mode 100644 index 0000000000..6c6d6d116c --- /dev/null +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/RendererVisitor.java @@ -0,0 +1,99 @@ +/* + * 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.server.widgetsetutils.metadata; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.TreeLogger.Type; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.core.ext.typeinfo.JType; +import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; + +/** + * Generates type data for renderer connectors. + *
    + *
  • Stores the return type of the overridden + * {@link AbstractRendererConnector#getRenderer() getRenderer} method to enable + * automatic creation of an instance of the proper renderer type. + *
  • Stores the presentation type of the connector to enable the + * {@link AbstractRendererConnector#decode(com.google.gwt.json.client.JSONValue) + * decode} method to work without having to implement a "getPresentationType" + * method. + *
+ * + * @see WidgetInitVisitor + * + * @since + * @author Vaadin Ltd + */ +public class RendererVisitor extends TypeVisitor { + + @Override + public void visitConnector(TreeLogger logger, JClassType type, + ConnectorBundle bundle) { + if (ConnectorBundle.isConnectedRendererConnector(type)) { + doRendererType(logger, type, bundle); + doPresentationType(logger, type, bundle); + } + } + + private static void doRendererType(TreeLogger logger, JClassType type, + ConnectorBundle bundle) { + // The class in which createRenderer is implemented + JClassType createRendererClass = ConnectorBundle.findInheritedMethod( + type, "createRenderer").getEnclosingType(); + + // Needs GWT constructor if createRenderer is not overridden + if (createRendererClass.getQualifiedSourceName().equals( + AbstractRendererConnector.class.getCanonicalName())) { + + JMethod getRenderer = ConnectorBundle.findInheritedMethod(type, + "getRenderer"); + JClassType rendererType = getRenderer.getReturnType().isClass(); + + bundle.setNeedsGwtConstructor(rendererType); + + // Also needs renderer type to find the right GWT constructor + bundle.setNeedsReturnType(type, getRenderer); + + logger.log(Type.DEBUG, "Renderer type of " + type + " is " + + rendererType); + } + } + + private void doPresentationType(TreeLogger logger, JClassType type, + ConnectorBundle bundle) { + JType presentationType = getPresentationType(type); + bundle.setPresentationType(type, presentationType); + + logger.log(Type.DEBUG, "Presentation type of " + type + " is " + + presentationType); + } + + private static JType getPresentationType(JClassType type) { + JClassType originalType = type; + while (type != null) { + if (type.getQualifiedBinaryName().equals( + AbstractRendererConnector.class.getName())) { + return type.isParameterized().getTypeArgs()[0]; + } + type = type.getSuperclass(); + } + throw new IllegalArgumentException("The type " + + originalType.getQualifiedSourceName() + " does not extend " + + AbstractRendererConnector.class.getName()); + } +} diff --git a/client/src/com/vaadin/client/metadata/TypeDataStore.java b/client/src/com/vaadin/client/metadata/TypeDataStore.java index 7aa952d0f2..9b1fd7d45c 100644 --- a/client/src/com/vaadin/client/metadata/TypeDataStore.java +++ b/client/src/com/vaadin/client/metadata/TypeDataStore.java @@ -37,6 +37,8 @@ public class TypeDataStore { .create(); private final FastStringMap delegateToWidgetProperties = FastStringMap .create(); + private final FastStringMap presentationTypes = FastStringMap + .create(); /** * Maps connector class -> state property name -> hander method data @@ -135,6 +137,10 @@ public class TypeDataStore { return get().delegateToWidgetProperties.get(type.getBaseTypeName()); } + public static Type getPresentationType(Class type) { + return get().presentationTypes.get(getType(type).getBaseTypeName()); + } + public void setDelegateToWidget(Class clazz, String propertyName, String delegateValue) { Type type = getType(clazz); @@ -150,6 +156,11 @@ public class TypeDataStore { typeProperties.push(propertyName); } + public void setPresentationType(Class type, Class presentationType) { + presentationTypes.put(getType(type).getBaseTypeName(), + getType(presentationType)); + } + public void setReturnType(Class type, String methodName, Type returnType) { returnTypes.put(new Method(getType(type), methodName).getLookupKey(), returnType); diff --git a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java index 8a8712372f..cad5af97df 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/AbstractRendererConnector.java @@ -23,6 +23,7 @@ import com.vaadin.client.extensions.AbstractExtensionConnector; import com.vaadin.client.metadata.NoDataException; import com.vaadin.client.metadata.Type; import com.vaadin.client.metadata.TypeData; +import com.vaadin.client.metadata.TypeDataStore; import com.vaadin.client.ui.grid.GridConnector; import com.vaadin.client.ui.grid.Renderer; @@ -44,6 +45,18 @@ public abstract class AbstractRendererConnector extends private Renderer renderer = null; + private final Type presentationType = TypeDataStore + .getPresentationType(this.getClass()); + + protected AbstractRendererConnector() { + if (presentationType == null) { + throw new IllegalStateException( + "No presentation type found for " + + Util.getSimpleName(this) + + ". This may be caused by some unspecified problem in widgetset compilation."); + } + } + /** * Returns the renderer associated with this renderer connector. *

@@ -109,14 +122,11 @@ public abstract class AbstractRendererConnector extends */ public T decode(JSONValue value) { @SuppressWarnings("unchecked") - T decodedValue = (T) JsonDecoder.decodeValue(new Type(getType()), - value, null, getConnection()); + T decodedValue = (T) JsonDecoder.decodeValue(presentationType, value, + null, getConnection()); return decodedValue; } - // TODO generate data type - protected abstract Class getType(); - @Override @Deprecated protected void extend(ServerConnector target) { diff --git a/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java index 84b261415b..9ec609ae06 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/TextRendererConnector.java @@ -30,9 +30,4 @@ public class TextRendererConnector extends AbstractRendererConnector { public TextRenderer getRenderer() { return (TextRenderer) super.getRenderer(); } - - @Override - public Class getType() { - return String.class; - } } diff --git a/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java b/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java index 7d5b9e1c60..1d4a8c0384 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/UnsafeHtmlRendererConnector.java @@ -40,9 +40,4 @@ public class UnsafeHtmlRendererConnector extends public UnsafeHtmlRenderer getRenderer() { return (UnsafeHtmlRenderer) super.getRenderer(); } - - @Override - public Class getType() { - return String.class; - } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java index dc424e7606..d6873ac0a5 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/IntArrayRendererConnector.java @@ -43,9 +43,4 @@ public class IntArrayRendererConnector extends AbstractRendererConnector public IntArrayRenderer getRenderer() { return (IntArrayRenderer) super.getRenderer(); } - - @Override - public Class getType() { - return int[].class; - } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java index 9ee05cb036..3880bacae2 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/RowAwareRendererConnector.java @@ -67,11 +67,6 @@ public class RowAwareRendererConnector extends AbstractRendererConnector { } } - @Override - protected Class getType() { - return Void.class; - } - @Override protected Renderer createRenderer() { // cannot use the default createRenderer as RowAwareRenderer needs a -- cgit v1.2.3 From 446c51e0f055aaf9d78020e9370e7d2dfbb451d1 Mon Sep 17 00:00:00 2001 From: Patrik Lindström Date: Wed, 16 Jul 2014 02:57:20 +0300 Subject: Add pure client-side test application for Grid (#13334) Change-Id: I853a91c20e80361ef5daeb31024597200acad1d9 --- .../basicfeatures/GridBasicClientFeaturesTest.java | 69 +++++ .../grid/basicfeatures/GridBasicFeaturesTest.java | 4 +- .../basicfeatures/GridClientSelectionTest.java | 35 +++ .../tests/widgetset/TestingWidgetSet.gwt.xml | 2 + .../client/grid/GridBasicClientFeatures.java | 254 +++++++++++++++++ .../grid/GridBasicClientFeaturesConnector.java | 36 +++ .../client/grid/PureGWTTestApplication.java | 308 +++++++++++++++++++++ .../server/grid/GridBasicClientFeatures.java | 41 +++ 8 files changed, 747 insertions(+), 2 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientSelectionTest.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesConnector.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/PureGWTTestApplication.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/server/grid/GridBasicClientFeatures.java (limited to 'uitest/src') 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..95b45b262e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java @@ -0,0 +1,69 @@ +/* + * 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.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.tests.components.grid.GridElement; +import com.vaadin.tests.widgetset.server.grid.GridBasicClientFeatures; + +/** + * 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 GridElement getGridElement() { + return ((TestBenchElement) findElement(By.className("v-grid"))) + .wrap(GridElement.class); + } + + @Override + protected void selectMenu(String menuCaption) { + WebElement menuElement = getMenuElement(menuCaption); + new Actions(getDriver()).moveToElement(menuElement).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()) + .moveToElement( + getMenuElement(menuCaptions[menuCaptions.length - 1])) + .click().perform(); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java index 3651a0c919..79501f50ac 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java @@ -33,12 +33,12 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { return GridBasicFeatures.class; } - private void selectSubMenu(String menuCaption) { + protected void selectSubMenu(String menuCaption) { selectMenu(menuCaption); new Actions(getDriver()).moveByOffset(100, 0).build().perform(); } - private void selectMenu(String menuCaption) { + protected void selectMenu(String menuCaption) { getDriver().findElement( By.xpath("//span[text() = '" + menuCaption + "']")).click(); } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientSelectionTest.java new file mode 100644 index 0000000000..cb70c28b7d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientSelectionTest.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 static org.junit.Assert.assertTrue; + +import org.junit.Test; + +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/widgetset/TestingWidgetSet.gwt.xml b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml index fd52e5cd0e..ac93efd7d4 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 @@ + + diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java new file mode 100644 index 0000000000..857ff14528 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -0,0 +1,254 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.client.grid; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Random; + +import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Grid; +import com.vaadin.client.ui.grid.Grid.SelectionMode; +import com.vaadin.client.ui.grid.GridColumn; +import com.vaadin.client.ui.grid.Renderer; +import com.vaadin.client.ui.grid.datasources.ListDataSource; +import com.vaadin.client.ui.grid.renderers.DateRenderer; +import com.vaadin.client.ui.grid.renderers.HtmlRenderer; +import com.vaadin.client.ui.grid.renderers.NumberRenderer; +import com.vaadin.client.ui.grid.renderers.TextRenderer; +import com.vaadin.tests.widgetset.client.grid.GridBasicClientFeatures.Data; + +/** + * Grid basic client features test application. + * + * @since + * @author Vaadin Ltd + */ +public class GridBasicClientFeatures extends + PureGWTTestApplication>> { + + public static enum Renderers { + TEXT_RENDERER, HTML_RENDERER, NUMBER_RENDERER, DATE_RENDERER; + } + + private static final int MANUALLY_FORMATTED_COLUMNS = 4; + public static final int COLUMNS = 11; + public static final int ROWS = 1000; + + private final Grid> grid; + private final List> data; + private final ListDataSource> ds; + + /** + * 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 createDataRow(int cols) { + List list = new ArrayList(cols); + for (int i = 0; i < cols; ++i) { + list.add(new Data()); + } + data.add(list); + return list; + } + + @SuppressWarnings("unchecked") + public GridBasicClientFeatures() { + super(new Grid>()); + + // Initialize data source + data = new ArrayList>(); + { + Random rand = new Random(); + rand.setSeed(13334); + long timestamp = 0; + for (int row = 0; row < ROWS; row++) { + + List 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 = "" + row + ""; + + d = datarow.get(col++); + d.value = Integer.valueOf(rand.nextInt()); + } + } + + ds = new ListDataSource>(data); + grid = getTestedWidget(); + grid.setDataSource(ds); + grid.setSelectionMode(SelectionMode.NONE); + + // 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; + + grid.addColumn(new GridColumn>( + createRenderer(Renderers.TEXT_RENDERER)) { + @Override + public String getValue(List row) { + return (String) row.get(c).value; + } + }); + + } + + // Integer row number + { + final int c = col++; + grid.addColumn(new GridColumn>( + createRenderer(Renderers.NUMBER_RENDERER)) { + @Override + public Integer getValue(List row) { + return (Integer) row.get(c).value; + } + }); + } + + // Some date + { + final int c = col++; + grid.addColumn(new GridColumn>( + createRenderer(Renderers.DATE_RENDERER)) { + @Override + public Date getValue(List row) { + return (Date) row.get(c).value; + } + }); + } + + // Row number as a HTML string + { + final int c = col++; + grid.addColumn(new GridColumn>( + createRenderer(Renderers.HTML_RENDERER)) { + @Override + public String getValue(List row) { + return (String) row.get(c).value; + } + }); + } + + // Random integer value + { + final int c = col++; + grid.addColumn(new GridColumn>( + createRenderer(Renderers.NUMBER_RENDERER)) { + @Override + public Integer getValue(List row) { + return (Integer) row.get(c).value; + } + }); + } + + // + // Populate the menu + // + + addMenuCommand("multi", new ScheduledCommand() { + @Override + public void execute() { + grid.setSelectionMode(SelectionMode.MULTI); + } + }, "Component", "State", "Selection mode"); + + addMenuCommand("single", new ScheduledCommand() { + + @Override + public void execute() { + grid.setSelectionMode(SelectionMode.SINGLE); + } + }, "Component", "State", "Selection mode"); + + addMenuCommand("none", new ScheduledCommand() { + + @Override + public void execute() { + grid.setSelectionMode(SelectionMode.NONE); + } + }, "Component", "State", "Selection mode"); + + grid.getElement().getStyle().setZIndex(0); + add(grid); + } + + /** + * Creates a 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, "" + htmlString + ""); + } + }; + + case NUMBER_RENDERER: + return new NumberRenderer(); + + case DATE_RENDERER: + return new DateRenderer(); + + default: + return new TextRenderer(); + } + } +} 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..4b640e84e5 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesConnector.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.widgetset.client.grid; + +import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.shared.ui.Connect; + +/** + * Connector for the GridClientBasicFeatures ApplicationWidget + * + * @since + * @author Vaadin Ltd + */ +@Connect(com.vaadin.tests.widgetset.server.grid.GridBasicClientFeatures.GridTestComponent.class) +public class GridBasicClientFeaturesConnector extends + AbstractComponentConnector { + + @Override + public GridBasicClientFeatures getWidget() { + return (GridBasicClientFeatures) super.getWidget(); + } + +} 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 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

children; + private final List 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(); + items = new ArrayList(); + } + + /** + * Create a sub-menu, with a title. + * + * @param title + */ + public Menu(String title) { + this.title = title; + menubar = new MenuBar(true); + children = new ArrayList(); + items = new ArrayList(); + } + + /** + * 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/server/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/server/grid/GridBasicClientFeatures.java new file mode 100644 index 0000000000..fb217dc232 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/server/grid/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.widgetset.server.grid; + +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()); + } + +} -- cgit v1.2.3 From 3626012f2ebf51c5433eb2671b5404e583a0f892 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 15 Jul 2014 14:36:01 +0300 Subject: Start rewrite of client-side Grid header/footer API (#13334) The old API is marked as deprecated and does not work anymore. Currently supported: * A single hard-coded header * Text captions TODO: * Footers * 0..n headers and footers * Column spanning * HTML content * Widget content * Component content * Sorting/Indicators * Server side API * Shared state handling Change-Id: I0448c36c8406807037b5e21e2db205a2ee24bc8a --- .../src/com/vaadin/client/ui/grid/ColumnGroup.java | 1 + .../com/vaadin/client/ui/grid/ColumnGroupRow.java | 1 + client/src/com/vaadin/client/ui/grid/Grid.java | 101 +++++++++-------- .../src/com/vaadin/client/ui/grid/GridHeader.java | 105 +++++++++++++++++ .../components/grid/GridSingleColumnTest.java | 5 + .../grid/basicfeatures/GridBasicFeaturesTest.java | 12 ++ .../grid/basicfeatures/GridHeaderTest.java | 36 ++++++ .../grid/basicfeatures/GridSortingTest.java | 5 + .../grid/basicfeatures/GridStructureTest.java | 125 ++------------------- 9 files changed, 228 insertions(+), 163 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/GridHeader.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/ColumnGroup.java b/client/src/com/vaadin/client/ui/grid/ColumnGroup.java index 13468a0d8e..af83730ceb 100644 --- a/client/src/com/vaadin/client/ui/grid/ColumnGroup.java +++ b/client/src/com/vaadin/client/ui/grid/ColumnGroup.java @@ -34,6 +34,7 @@ import com.vaadin.client.ui.grid.renderers.TextRenderer; * @author Vaadin Ltd * @see ColumnGroupRow#addGroup(ColumnGroup...) */ +@Deprecated public class ColumnGroup { /** diff --git a/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java b/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java index 3c621fdd15..bae6a732e6 100644 --- a/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java +++ b/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java @@ -33,6 +33,7 @@ import java.util.Set; * @since * @author Vaadin Ltd */ +@Deprecated public class ColumnGroupRow { /** diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 471f62cdeb..539c18f8c8 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -192,6 +192,8 @@ public class Grid extends Composite implements */ private Escalator escalator = GWT.create(Escalator.class); + private GridHeader header = GWT.create(GridHeader.class); + /** * List of columns in the grid. Order defines the visible order. */ @@ -206,16 +208,19 @@ public class Grid extends Composite implements /** * The column groups rows added to the grid */ + @Deprecated private final List> columnGroupRows = new ArrayList>(); /** * Are the headers for the columns visible */ + @Deprecated private boolean columnHeadersVisible = true; /** * Are the footers for the columns visible */ + @Deprecated private boolean columnFootersVisible = false; /** @@ -574,11 +579,13 @@ public class Grid extends Composite implements /** * The text displayed in the header of the column */ + @Deprecated private String header; /** * Text displayed in the column footer */ + @Deprecated private String footer; /** @@ -594,12 +601,14 @@ public class Grid extends Composite implements /** * Renderer for rendering the header cell value into the cell */ + @Deprecated private Renderer headerRenderer = new SortableColumnHeaderRenderer( new TextRenderer()); /** * Renderer for rendering the footer cell value into the cell */ + @Deprecated private Renderer footerRenderer = new TextRenderer(); private boolean sortable = false; @@ -661,6 +670,7 @@ public class Grid extends Composite implements * * @return the text displayed in the column caption */ + @Deprecated public String getHeaderCaption() { return header; } @@ -670,6 +680,7 @@ public class Grid extends Composite implements * * @return a renderer that renders header cells */ + @Deprecated public Renderer getHeaderRenderer() { return headerRenderer; } @@ -680,6 +691,7 @@ public class Grid extends Composite implements * @param renderer * The renderer to use for rendering header cells. */ + @Deprecated public void setHeaderRenderer(Renderer renderer) { if (renderer == null) { throw new IllegalArgumentException("Renderer cannot be null."); @@ -695,6 +707,7 @@ public class Grid extends Composite implements * * @return a renderer that renders footer cells */ + @Deprecated public Renderer getFooterRenderer() { return footerRenderer; } @@ -705,6 +718,7 @@ public class Grid extends Composite implements * @param renderer * The renderer to use for rendering footer cells. */ + @Deprecated public void setFooterRenderer(Renderer renderer) { if (renderer == null) { throw new IllegalArgumentException("Renderer cannot be null."); @@ -721,6 +735,7 @@ public class Grid extends Composite implements * @param caption * the text displayed in the column header */ + @Deprecated public void setHeaderCaption(String caption) { if (SharedUtil.equals(caption, header)) { return; @@ -739,6 +754,7 @@ public class Grid extends Composite implements * * @return The text displayed in the footer of the column */ + @Deprecated public String getFooterCaption() { return footer; } @@ -749,6 +765,7 @@ public class Grid extends Composite implements * @param caption * the text displayed in the footer of the column */ + @Deprecated public void setFooterCaption(String caption) { if (SharedUtil.equals(caption, footer)) { return; @@ -898,6 +915,7 @@ public class Grid extends Composite implements /** * Base class for header / footer escalator updater */ + @Deprecated protected abstract class HeaderFooterEscalatorUpdater implements EscalatorUpdater { @@ -1125,36 +1143,44 @@ public class Grid extends Composite implements * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createHeaderUpdater() { - return new HeaderFooterEscalatorUpdater(escalator.getHeader(), true) { + return new EscalatorUpdater() { @Override - public boolean isRowVisible(ColumnGroupRow row) { - return row.isHeaderVisible(); - } + public void update(Row row, Iterable cellsToUpdate) { + GridHeader.HeaderRow headerRow = header.getRow(row.getRow()); - @Override - public String getGroupValue(ColumnGroup group) { - return group.getHeaderCaption(); + int colIndex = -1; + for (FlyweightCell cell : cellsToUpdate) { + if (colIndex == -1) { + colIndex = cell.getColumn(); + } + while (!columns.get(colIndex).isVisible()) { + colIndex++; + } + + headerRow.getRenderer().render(cell, + headerRow.getCell(colIndex).getText()); + + colIndex++; + } } @Override - public String getColumnValue(GridColumn column) { - return column.getHeaderCaption(); + public void preAttach(Row row, Iterable cellsToAttach) { } @Override - public boolean firstRowIsVisible() { - return isColumnHeadersVisible(); + public void postAttach(Row row, + Iterable attachedCells) { } @Override - public Renderer getRenderer(GridColumn column) { - return column.getHeaderRenderer(); + public void preDetach(Row row, Iterable cellsToDetach) { } @Override - public Renderer getGroupRenderer(ColumnGroup group) { - return group.getHeaderRenderer(); + public void postDetach(Row row, + Iterable detachedCells) { } }; } @@ -1306,38 +1332,7 @@ public class Grid extends Composite implements * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createFooterUpdater() { - return new HeaderFooterEscalatorUpdater(escalator.getFooter(), false) { - - @Override - public boolean isRowVisible(ColumnGroupRow row) { - return row.isFooterVisible(); - } - - @Override - public String getGroupValue(ColumnGroup group) { - return group.getFooterCaption(); - } - - @Override - public String getColumnValue(GridColumn column) { - return column.getFooterCaption(); - } - - @Override - public boolean firstRowIsVisible() { - return isColumnFootersVisible(); - } - - @Override - public Renderer getRenderer(GridColumn column) { - return column.getFooterRenderer(); - } - - @Override - public Renderer getGroupRenderer(ColumnGroup group) { - return group.getFooterRenderer(); - } - }; + return EscalatorUpdater.NULL; } /** @@ -1437,6 +1432,8 @@ public class Grid extends Composite implements // Register column with grid columns.add(index, column); + header.addColumn(column, index); + // Register this grid instance with the column ((AbstractGridColumn) column).setGrid(this); @@ -1537,6 +1534,7 @@ public class Grid extends Composite implements int columnIndex = columns.indexOf(column); int visibleIndex = findVisibleColumnIndex(column); columns.remove(columnIndex); + header.removeColumn(columnIndex); // de-register column with grid ((AbstractGridColumn) column).setGrid(null); @@ -1618,6 +1616,7 @@ public class Grid extends Composite implements * @param visible * true if header rows should be visible */ + @Deprecated public void setColumnHeadersVisible(boolean visible) { if (visible == isColumnHeadersVisible()) { return; @@ -1631,6 +1630,7 @@ public class Grid extends Composite implements * * @return true if they are visible */ + @Deprecated public boolean isColumnHeadersVisible() { return columnHeadersVisible; } @@ -1664,6 +1664,7 @@ public class Grid extends Composite implements * @param visible * true if the footer row should be visible */ + @Deprecated public void setColumnFootersVisible(boolean visible) { if (visible == isColumnFootersVisible()) { return; @@ -1678,6 +1679,7 @@ public class Grid extends Composite implements * @return true if they are visible * */ + @Deprecated public boolean isColumnFootersVisible() { return columnFootersVisible; } @@ -1709,6 +1711,7 @@ public class Grid extends Composite implements * * @return a column group row instance you can use to add column groups */ + @Deprecated public ColumnGroupRow addColumnGroupRow() { ColumnGroupRow row = new ColumnGroupRow(this); columnGroupRows.add(row); @@ -1727,6 +1730,7 @@ public class Grid extends Composite implements * the index where the column group row should be added * @return a column group row instance you can use to add column groups */ + @Deprecated public ColumnGroupRow addColumnGroupRow(int rowIndex) { ColumnGroupRow row = new ColumnGroupRow(this); columnGroupRows.add(rowIndex, row); @@ -1741,6 +1745,7 @@ public class Grid extends Composite implements * @param row * The row to remove */ + @Deprecated public void removeColumnGroupRow(ColumnGroupRow row) { columnGroupRows.remove(row); refreshHeader(); @@ -1753,6 +1758,7 @@ public class Grid extends Composite implements * @return a unmodifiable list of column group rows * */ + @Deprecated public List> getColumnGroupRows() { return Collections.unmodifiableList(new ArrayList>( columnGroupRows)); @@ -1768,6 +1774,7 @@ public class Grid extends Composite implements * @return A column group for the row and column or null if not * found. */ + @Deprecated private ColumnGroup getGroupForColumn(ColumnGroupRow row, GridColumn column) { for (ColumnGroup group : row.getGroups()) { diff --git a/client/src/com/vaadin/client/ui/grid/GridHeader.java b/client/src/com/vaadin/client/ui/grid/GridHeader.java new file mode 100644 index 0000000000..023973c511 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/GridHeader.java @@ -0,0 +1,105 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.vaadin.client.ui.grid.renderers.TextRenderer; + +/** + * Represents the header section of a Grid. A header consists of a single header + * row containing a header cell for each column. Each cell has a simple textual + * caption. + * + * TODO Arbitrary number of header rows (zero included) + * + * TODO Merging header cells + * + * TODO "Default" row with sorting + * + * TODO Widgets in cells + * + * TODO HTML in cells + * + * @since + * @author Vaadin Ltd + */ +public class GridHeader { + + /** + * A single row in a grid header section. + * + * @since + * @author Vaadin Ltd + */ + public static class HeaderRow { + + private List cells = new ArrayList(); + + private Renderer renderer = new TextRenderer(); + + public HeaderCell getCell(int index) { + return cells.get(index); + } + + protected void addCell(int index) { + cells.add(index, new HeaderCell()); + } + + protected void removeCell(int index) { + cells.remove(index); + } + + protected Renderer getRenderer() { + return renderer; + } + } + + /** + * A single cell in a grid header row. Has a textual caption. + * + * @since + * @author Vaadin Ltd + */ + public static class HeaderCell { + + private String text = ""; + + public void setText(String text) { + this.text = text; + } + + public String getText() { + return text; + } + } + + private List rows = Arrays.asList(new HeaderRow()); + + public HeaderRow getRow(int index) { + return rows.get(index); + } + + protected void addColumn(GridColumn column, int index) { + getRow(0).addCell(index); + } + + protected void removeColumn(int index) { + getRow(0).removeCell(index); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java index 10d2c8592a..2e062f36c6 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridSingleColumnTest.java @@ -18,6 +18,7 @@ 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; @@ -28,7 +29,11 @@ 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(); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java index 79501f50ac..a3c62e0303 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java @@ -15,12 +15,16 @@ */ 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 com.vaadin.testbench.TestBenchElement; import com.vaadin.tests.annotations.TestCategory; import com.vaadin.tests.components.grid.GridElement; import com.vaadin.tests.tb3.MultiBrowserTest; @@ -59,6 +63,14 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { getGridVerticalScrollbar()); } + protected List getGridHeaderRowCells() { + List headerCells = new ArrayList(); + for (int i = 0; i < getGridElement().getHeaderCount(); ++i) { + headerCells.addAll(getGridElement().getHeaderCells(i)); + } + return headerCells; + } + private Object executeScript(String script, WebElement element) { final WebDriver driver = getDriver(); if (driver instanceof JavascriptExecutor) { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java new file mode 100644 index 0000000000..dfbb1679b0 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.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 static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Test; + +import com.vaadin.testbench.TestBenchElement; + +public class GridHeaderTest extends GridBasicClientFeaturesTest { + + @Test + public void testHeaderVisible() throws Exception { + openTestURL(); + + // Column headers should be visible + List cells = getGridHeaderRowCells(); + assertEquals(GridBasicFeatures.COLUMNS, cells.size()); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java index 820070f933..f706c1791d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java @@ -21,13 +21,18 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; +import org.junit.Ignore; import org.junit.Test; import com.vaadin.tests.components.grid.GridElement; public class GridSortingTest extends GridBasicFeaturesTest { + /* + * TODO unignore once column header captions are reimplemented + */ @Test + @Ignore public void testProgrammaticSorting() throws IOException { openTestURL(); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java index 17438fd4bb..94f04e10a2 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java @@ -20,117 +20,22 @@ import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import java.util.ArrayList; import java.util.List; +import org.junit.Ignore; 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.GridBasicFeatures; -import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; public class GridStructureTest extends GridBasicFeaturesTest { + /* + * TODO unignore once column header captions are reimplemented + */ @Test - public void testColumnHeaderCaptions() throws Exception { - openTestURL(); - - // Column headers should be visible - List cells = getGridHeaderRowCells(); - assertEquals(GridBasicFeatures.COLUMNS, cells.size()); - assertEquals("Column0", cells.get(0).getText()); - assertEquals("Column1", cells.get(1).getText()); - assertEquals("Column2", cells.get(2).getText()); - } - - @Test - public void testColumnFooterCaptions() throws Exception { - openTestURL(); - - // footer row should by default be hidden - List cells = getGridFooterRowCells(); - assertEquals(0, cells.size()); - - // Open footer row - selectMenuPath("Component", "Footers", "Visible"); - - // Footers should now be visible - cells = getGridFooterRowCells(); - assertEquals(GridBasicFeatures.COLUMNS, cells.size()); - assertEquals("Footer 0", cells.get(0).getText()); - assertEquals("Footer 1", cells.get(1).getText()); - assertEquals("Footer 2", cells.get(2).getText()); - } - - @Test - public void testColumnGroupHeaders() throws Exception { - openTestURL(); - - // Hide column headers for this test - selectMenuPath("Component", "Headers", "Visible"); - - List cells = getGridHeaderRowCells(); - - // header row should be empty - assertEquals(0, cells.size()); - - // add a group row - selectMenuPath("Component", "Column groups", "Add group row"); - - // Empty group row cells should be present - cells = getGridHeaderRowCells(); - assertEquals(GridBasicFeatures.COLUMNS, cells.size()); - - // Group columns 0 & 1 - selectMenuPath("Component", "Column groups", "Column group row 1", - "Group Column 0 & 1"); - - cells = getGridHeaderRowCells(); - assertEquals("Column 0 & 1", cells.get(0).getText()); - } - - @Test - public void testColumnGroupFooters() throws Exception { - openTestURL(); - - // add a group row - selectMenuPath("Component", "Column groups", "Add group row"); - - // Set footer visible - selectMenuPath("Component", "Column groups", "Column group row 1", - "Footer Visible"); - - // Group columns 0 & 1 - selectMenuPath("Component", "Column groups", "Column group row 1", - "Group Column 0 & 1"); - - List cells = getGridFooterRowCells(); - assertEquals("Column 0 & 1", cells.get(0).getText()); - } - - @Test - public void testGroupingSameColumnsOnRowThrowsException() throws Exception { - openTestURL(); - - // add a group row - selectMenuPath("Component", "Column groups", "Add group row"); - - // Group columns 0 & 1 - selectMenuPath("Component", "Column groups", "Column group row 1", - "Group Column 0 & 1"); - - // Group columns 1 & 2 shoud fail - selectMenuPath("Component", "Column groups", "Column group row 1", - "Group Column 1 & 2"); - - assertTrue(getLogRow(0) - .contains( - "Exception occured, java.lang.IllegalArgumentExceptionColumn Column1 already belongs to another group.")); - } - - @Test + @Ignore public void testHidingColumn() throws Exception { openTestURL(); @@ -146,7 +51,11 @@ public class GridStructureTest extends GridBasicFeaturesTest { assertEquals("Column1", cells.get(0).getText()); } + /* + * TODO unignore once column header captions are reimplemented + */ @Test + @Ignore public void testRemovingColumn() throws Exception { openTestURL(); @@ -328,20 +237,4 @@ public class GridStructureTest extends GridBasicFeaturesTest { private WebElement getTableWrapper() { return getGridElement().findElement(By.xpath("./div[3]")); } - - private List getGridHeaderRowCells() { - List headerCells = new ArrayList(); - for (int i = 0; i < getGridElement().getHeaderCount(); ++i) { - headerCells.addAll(getGridElement().getHeaderCells(i)); - } - return headerCells; - } - - private List getGridFooterRowCells() { - List footerCells = new ArrayList(); - for (int i = 0; i < getGridElement().getFooterCount(); ++i) { - footerCells.addAll(getGridElement().getFooterCells(i)); - } - return footerCells; - } } -- cgit v1.2.3 From a9c124cc19b4e1bf1c8736e209b8e066a002da6f Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 16 Jul 2014 15:44:27 +0300 Subject: Implement active cell keyboard navigation for Grid (#13334) Change-Id: I38b759f24fa35432d5bc330b06a64caaa7ef3c9e --- client/src/com/vaadin/client/ui/grid/Grid.java | 297 ++++++++++++++++----- .../basicfeatures/GridKeyboardNavigationTest.java | 56 +++- 2 files changed, 292 insertions(+), 61 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 539c18f8c8..5ef94a296c 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -32,6 +32,7 @@ import com.google.gwt.dom.client.EventTarget; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.dom.client.Touch; +import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.touch.client.Point; import com.google.gwt.user.client.DOM; @@ -100,6 +101,222 @@ import com.vaadin.shared.util.SharedUtil; public class Grid extends Composite implements HasSelectionChangeHandlers, SubPartAware { + private class ActiveCellHandler { + + private RowContainer container = escalator.getBody(); + private int activeRow = 0; + private int activeColumn = 0; + private Element cellWithActiveStyle = null; + private Element rowWithActiveStyle = null; + + public ActiveCellHandler() { + sinkEvents(getNavigationEvents()); + } + + /** + * Sets style names for given cell when needed. + */ + public void updateActiveCellStyle(FlyweightCell cell) { + int cellRow = cell.getRow(); + int cellColumn = cell.getColumn(); + RowContainer cellContainer = escalator.findRowContainer(cell + .getElement()); + + if (cellContainer == container) { + // Cell is in the current container + if (cellRow == activeRow && cellColumn == activeColumn) { + if (cellWithActiveStyle != cell.getElement()) { + // Cell is correct but it does not have active style + if (cellWithActiveStyle != null) { + // Remove old active style + setStyleName(cellWithActiveStyle, + cellActiveStyleName, false); + } + cellWithActiveStyle = cell.getElement(); + // Add active style to correct cell. + setStyleName(cellWithActiveStyle, cellActiveStyleName, + true); + } + } else if (cellWithActiveStyle == cell.getElement()) { + // Due to escalator reusing cells, a new cell has the same + // element but is not the active cell. + setStyleName(cellWithActiveStyle, cellActiveStyleName, + false); + cellWithActiveStyle = null; + } + } + + if (cellContainer == escalator.getHeader() + || cellContainer == escalator.getFooter()) { + // Correct header and footer column also needs highlighting + setStyleName(cell.getElement(), headerFooterActiveStyleName, + cellColumn == activeColumn); + } + } + + /** + * Sets active row style name for given row if needed. + * + * @param row + * a row object + */ + public void updateActiveRowStyle(Row row) { + if (activeRow == row.getRow() && container == escalator.getBody()) { + if (row.getElement() != rowWithActiveStyle) { + // Row should have active style but does not have it. + if (rowWithActiveStyle != null) { + setStyleName(rowWithActiveStyle, rowActiveStyleName, + false); + } + rowWithActiveStyle = row.getElement(); + setStyleName(rowWithActiveStyle, rowActiveStyleName, true); + } + } else if (rowWithActiveStyle == row.getElement() + || (container != escalator.getBody() && rowWithActiveStyle != null)) { + // Remove active style. + setStyleName(rowWithActiveStyle, rowActiveStyleName, false); + rowWithActiveStyle = null; + } + } + + /** + * Sets currently active cell to a cell in given container with given + * indices. + * + * @param row + * new active row + * @param column + * new active column + * @param container + * new container + */ + private void setActiveCell(int row, int column, RowContainer container) { + if (row == activeRow && column == activeColumn + && container == this.container) { + return; + } + + int oldRow = activeRow; + int oldColumn = activeColumn; + activeRow = row; + activeColumn = column; + + if (container == escalator.getBody()) { + scrollToRow(activeRow); + } + escalator.scrollToColumn(activeColumn, ScrollDestination.ANY, 10); + + if (this.container == container) { + if (container != escalator.getBody()) { + if (oldColumn == activeColumn && oldRow != activeRow) { + refreshRow(oldRow); + } else if (oldColumn != activeColumn) { + refreshHeader(); + refreshFooter(); + } + } else { + if (oldRow != activeRow) { + refreshRow(oldRow); + } + + if (oldColumn != activeColumn) { + refreshHeader(); + refreshFooter(); + } + } + } else { + RowContainer oldContainer = this.container; + this.container = container; + + if (oldColumn != activeColumn) { + refreshHeader(); + refreshFooter(); + if (oldContainer == escalator.getBody()) { + oldContainer.refreshRows(oldRow, 1); + } + } else { + oldContainer.refreshRows(oldRow, 1); + } + } + refreshRow(activeRow); + } + + /** + * Sets currently active cell used for keyboard navigation. Note that + * active cell is not JavaScript {@code document.activeElement}. + * + * @param cell + * a cell object + */ + public void setActiveCell(Cell cell) { + setActiveCell(cell.getRow(), cell.getColumn(), + escalator.findRowContainer(cell.getElement())); + } + + /** + * Gets list of events that can be used for active cell navigation. + * + * @return list of navigation related event types + */ + public Collection getNavigationEvents() { + return Arrays.asList(BrowserEvents.KEYDOWN, BrowserEvents.CLICK); + } + + /** + * Handle events that can change the currently active cell. + */ + public void handleNavigationEvent(Event event, Cell cell) { + if (event.getType().equals(BrowserEvents.CLICK) + && event.getButton() == NativeEvent.BUTTON_LEFT + && cell != null) { + setActiveCell(cell); + getElement().focus(); + } else if (event.getType().equals(BrowserEvents.KEYDOWN)) { + int keyCode = event.getKeyCode(); + if (keyCode == 0) { + keyCode = event.getCharCode(); + } + int newRow = activeRow; + int newColumn = activeColumn; + RowContainer newContainer = container; + + switch (event.getKeyCode()) { + case KeyCodes.KEY_DOWN: + newRow += 1; + break; + case KeyCodes.KEY_UP: + newRow -= 1; + break; + case KeyCodes.KEY_RIGHT: + newColumn += 1; + break; + case KeyCodes.KEY_LEFT: + newColumn -= 1; + break; + } + + if (newRow < 0) { + newRow = 0; + } else if (newRow >= container.getRowCount()) { + newRow = container.getRowCount() - 1; + } + + if (newColumn < 0) { + newColumn = 0; + } else if (newColumn >= getColumnCount()) { + newColumn = getColumnCount() - 1; + } + + setActiveCell(newRow, newColumn, newContainer); + } + + } + + private void refreshRow(int row) { + container.refreshRows(row, 1); + } + } + private class SelectionColumn extends GridColumn { private boolean initDone = false; @@ -242,18 +459,14 @@ public class Grid extends Composite implements private String rowSelectedStyleName; private String cellActiveStyleName; private String rowActiveStyleName; - private String headerFooterFocusedStyleName; + private String headerFooterActiveStyleName; /** * Current selection model. */ private SelectionModel selectionModel; - /** - * Current active cell. - */ - private int activeRow = 0; - private int activeColumn = 0; + private final ActiveCellHandler activeCellHandler; /** * Enumeration for easy setting of selection mode. @@ -1017,9 +1230,7 @@ public class Grid extends Composite implements .render(cell, getColumnValue(column)); } - setStyleName(cell.getElement(), - headerFooterFocusedStyleName, - activeColumn == cell.getColumn()); + activeCellHandler.updateActiveCellStyle(cell); } } else if (columnGroupRows.size() > 0) { @@ -1058,9 +1269,7 @@ public class Grid extends Composite implements cellElement.setInnerHTML(null); cell.setColSpan(1); - setStyleName(cell.getElement(), - headerFooterFocusedStyleName, - activeColumn == cell.getColumn()); + activeCellHandler.updateActiveCellStyle(cell); } } } @@ -1088,6 +1297,8 @@ public class Grid extends Composite implements */ public Grid() { initWidget(escalator); + getElement().setTabIndex(0); + activeCellHandler = new ActiveCellHandler(); setStylePrimaryName("v-grid"); @@ -1098,7 +1309,6 @@ public class Grid extends Composite implements refreshHeader(); refreshFooter(); - sinkEvents(Event.ONMOUSEDOWN); setSelectionMode(SelectionMode.SINGLE); escalator @@ -1132,7 +1342,7 @@ public class Grid extends Composite implements rowHasDataStyleName = getStylePrimaryName() + "-row-has-data"; rowSelectedStyleName = getStylePrimaryName() + "-row-selected"; cellActiveStyleName = getStylePrimaryName() + "-cell-active"; - headerFooterFocusedStyleName = getStylePrimaryName() + "-header-active"; + headerFooterActiveStyleName = getStylePrimaryName() + "-header-active"; rowActiveStyleName = getStylePrimaryName() + "-row-active"; } @@ -1151,6 +1361,8 @@ public class Grid extends Composite implements int colIndex = -1; for (FlyweightCell cell : cellsToUpdate) { + activeCellHandler.updateActiveCellStyle(cell); + if (colIndex == -1) { colIndex = cell.getColumn(); } @@ -1244,8 +1456,7 @@ public class Grid extends Composite implements setStyleName(rowElement, rowSelectedStyleName, false); } - setStyleName(rowElement, rowActiveStyleName, - rowIndex == activeRow); + activeCellHandler.updateActiveRowStyle(row); for (FlyweightCell cell : cellsToUpdate) { GridColumn column = getColumnFromVisibleIndex(cell @@ -1254,8 +1465,7 @@ public class Grid extends Composite implements assert column != null : "Column was not found from cell (" + cell.getColumn() + "," + cell.getRow() + ")"; - setStyleName(cell.getElement(), cellActiveStyleName, - isActiveCell(cell)); + activeCellHandler.updateActiveCellStyle(cell); Renderer renderer = column.getRenderer(); @@ -1288,11 +1498,6 @@ public class Grid extends Composite implements } } - private boolean isActiveCell(FlyweightCell cell) { - return cell.getRow() == activeRow - && cell.getColumn() == activeColumn; - } - @Override public void preDetach(Row row, Iterable cellsToDetach) { for (FlyweightCell cell : cellsToDetach) { @@ -2122,8 +2327,9 @@ public class Grid extends Composite implements if (Element.is(target)) { Element e = Element.as(target); RowContainer container = escalator.findRowContainer(e); + Cell cell = null; if (container != null) { - Cell cell = container.getCell(e); + cell = container.getCell(e); if (cell != null) { GridColumn gridColumn = columns.get(cell.getColumn()); @@ -2145,14 +2351,13 @@ public class Grid extends Composite implements } } } - - // TODO: Support active cells in Headers and Footers, - // 14.07.2014, Teemu Suo-Anttila - if (event.getTypeInt() == Event.ONMOUSEDOWN) { - setActiveCell(cell); - } } } + + if (activeCellHandler.getNavigationEvents().contains( + event.getType())) { + activeCellHandler.handleNavigationEvent(event, cell); + } } } @@ -2255,13 +2460,13 @@ public class Grid extends Composite implements if (this.selectColumnRenderer != null) { removeColumnSkipSelectionColumnCheck(selectionColumn); - --activeColumn; + --activeCellHandler.activeColumn; } this.selectColumnRenderer = selectColumnRenderer; if (selectColumnRenderer != null) { - ++activeColumn; + ++activeCellHandler.activeColumn; selectionColumn = new SelectionColumn(selectColumnRenderer); // FIXME: this needs to be done elsewhere, requires design... @@ -2508,32 +2713,4 @@ public class Grid extends Composite implements fireEvent(new SortEvent(this, Collections.unmodifiableList(sortOrder))); } - - /** - * Set currently active cell used for keyboard navigation. Note that active - * cell is not {@code activeElement}. - * - * @param cell - * a cell object - */ - public void setActiveCell(Cell cell) { - int oldRow = activeRow; - int oldColumn = activeColumn; - - activeRow = cell.getRow(); - activeColumn = cell.getColumn(); - - if (oldRow != activeRow) { - escalator.getBody().refreshRows(oldRow, 1); - escalator.getBody().refreshRows(activeRow, 1); - } - - if (oldColumn != activeColumn) { - if (oldRow == activeRow) { - escalator.getBody().refreshRows(oldRow, 1); - } - refreshHeader(); - refreshFooter(); - } - } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java index a297187b62..465fdedad6 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java @@ -18,7 +18,13 @@ package com.vaadin.tests.components.grid.basicfeatures; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.io.IOException; + +import org.junit.Ignore; 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; @@ -46,7 +52,55 @@ public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { assertTrue("Body cell 0, 0 is not active on init.", grid.getCell(0, 0) .isActive()); grid.getHeaderCell(0, 3).click(); - assertTrue("Body cell 0, 0 is not active after click on header.", grid + 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()); + + Actions manyClicks = new Actions(getDriver()); + int i; + for (i = 1; i < 40; ++i) { + manyClicks.sendKeys(Keys.ARROW_DOWN); + } + manyClicks.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 + @Ignore("This feature is still on the TODO list") + public void testNavigateFromHeaderToBody() throws IOException { + openTestURL(); + + GridElement grid = getGridElement(); + grid.scrollToRow(300); + grid.getHeaderCell(0, 7).click(); + + assertTrue("Header cell is not active.", grid.getHeaderCell(0, 7) + .isActive()); + new Actions(getDriver()).sendKeys(Keys.ARROW_DOWN).perform(); + assertTrue("Body cell 282, 7 is not active", grid.getCell(282, 7) + .isActive()); } } -- cgit v1.2.3 From f49e1227ae149833e50188fd21a0d6461af0c25a Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 15 Jul 2014 19:35:31 +0300 Subject: Client-side Grid header/footer rewrite: add simple footer support (#13334) Currently supported: * A single-row hard-coded header * A zero-row hard-coded footer * Text captions TODO: * 0..n headers and footers * Column spanning * HTML content * Widget content * Component content * Sorting/Indicators * Server side API * Shared state handling Change-Id: Ic85051b16ef77791f1fdae78fca47a0729e1c43d --- client/src/com/vaadin/client/ui/grid/Grid.java | 141 ++++++++++++--------- .../src/com/vaadin/client/ui/grid/GridFooter.java | 66 ++++++++++ .../src/com/vaadin/client/ui/grid/GridHeader.java | 63 ++------- .../vaadin/client/ui/grid/GridStaticSection.java | 141 +++++++++++++++++++++ .../grid/basicfeatures/GridBasicFeaturesTest.java | 8 ++ .../grid/basicfeatures/GridFooterTest.java | 36 ++++++ .../grid/basicfeatures/GridHeaderTest.java | 47 ++++++- .../client/grid/GridBasicClientFeatures.java | 41 +++++- 8 files changed, 427 insertions(+), 116 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/GridFooter.java create mode 100644 client/src/com/vaadin/client/ui/grid/GridStaticSection.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 5ef94a296c..1edd70daac 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -45,6 +45,7 @@ import com.vaadin.client.Util; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.SubPartAware; +import com.vaadin.client.ui.grid.GridStaticSection.StaticRow; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.TextRenderer; import com.vaadin.client.ui.grid.renderers.WidgetRenderer; @@ -409,7 +410,9 @@ public class Grid extends Composite implements */ private Escalator escalator = GWT.create(Escalator.class); - private GridHeader header = GWT.create(GridHeader.class); + private final GridHeader header = GWT.create(GridHeader.class); + + private final GridFooter footer = GWT.create(GridFooter.class); /** * List of columns in the grid. Order defines the visible order. @@ -1292,6 +1295,57 @@ public class Grid extends Composite implements } } + protected class StaticSectionUpdater implements EscalatorUpdater { + + private GridStaticSection section; + + public StaticSectionUpdater(GridStaticSection section) { + super(); + this.section = section; + } + + @Override + public void update(Row row, Iterable cellsToUpdate) { + StaticRow gridRow = section.getRow(row.getRow()); + + final List columnIndices = getVisibleColumnIndices(); + + for (FlyweightCell cell : cellsToUpdate) { + int index = columnIndices.get(cell.getColumn()); + gridRow.getRenderer().render(cell, + gridRow.getCell(index).getText()); + + activeCellHandler.updateActiveCellStyle(cell); + } + } + + @Override + public void preAttach(Row row, Iterable cellsToAttach) { + } + + @Override + public void postAttach(Row row, Iterable attachedCells) { + } + + @Override + public void preDetach(Row row, Iterable cellsToDetach) { + } + + @Override + public void postDetach(Row row, Iterable detachedCells) { + } + + private List getVisibleColumnIndices() { + List indices = new ArrayList(getColumnCount()); + for (int i = 0; i < getColumnCount(); i++) { + if (getColumn(i).isVisible()) { + indices.add(i); + } + } + return indices; + } + }; + /** * Creates a new instance. */ @@ -1353,48 +1407,7 @@ public class Grid extends Composite implements * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createHeaderUpdater() { - return new EscalatorUpdater() { - - @Override - public void update(Row row, Iterable cellsToUpdate) { - GridHeader.HeaderRow headerRow = header.getRow(row.getRow()); - - int colIndex = -1; - for (FlyweightCell cell : cellsToUpdate) { - activeCellHandler.updateActiveCellStyle(cell); - - if (colIndex == -1) { - colIndex = cell.getColumn(); - } - while (!columns.get(colIndex).isVisible()) { - colIndex++; - } - - headerRow.getRenderer().render(cell, - headerRow.getCell(colIndex).getText()); - - colIndex++; - } - } - - @Override - public void preAttach(Row row, Iterable cellsToAttach) { - } - - @Override - public void postAttach(Row row, - Iterable attachedCells) { - } - - @Override - public void preDetach(Row row, Iterable cellsToDetach) { - } - - @Override - public void postDetach(Row row, - Iterable detachedCells) { - } - }; + return new StaticSectionUpdater(header); } private EscalatorUpdater createBodyUpdater() { @@ -1537,7 +1550,7 @@ public class Grid extends Composite implements * @return the updater that updates the data in the escalator. */ private EscalatorUpdater createFooterUpdater() { - return EscalatorUpdater.NULL; + return new StaticSectionUpdater(footer); } /** @@ -1552,18 +1565,10 @@ public class Grid extends Composite implements * the footer */ private void refreshRowContainer(RowContainer rows, - boolean firstRowIsVisible, boolean isHeader) { - - // Count needed rows - int totalRows = firstRowIsVisible ? 1 : 0; - for (ColumnGroupRow row : columnGroupRows) { - if (isHeader ? row.isHeaderVisible() : row.isFooterVisible()) { - totalRows++; - } - } + GridStaticSection section) { // Add or Remove rows on demand - int rowDiff = totalRows - rows.getRowCount(); + int rowDiff = section.getRows().size() - rows.getRowCount(); if (rowDiff > 0) { rows.insertRows(0, rowDiff); } else if (rowDiff < 0) { @@ -1580,8 +1585,7 @@ public class Grid extends Composite implements * Refreshes all header rows */ void refreshHeader() { - refreshRowContainer(escalator.getHeader(), isColumnHeadersVisible(), - true); + refreshRowContainer(escalator.getHeader(), header); } /** @@ -1595,8 +1599,7 @@ public class Grid extends Composite implements * Refreshes all footer rows */ void refreshFooter() { - refreshRowContainer(escalator.getFooter(), isColumnFootersVisible(), - false); + refreshRowContainer(escalator.getFooter(), footer); } /** @@ -1638,6 +1641,7 @@ public class Grid extends Composite implements columns.add(index, column); header.addColumn(column, index); + footer.addColumn(column, index); // Register this grid instance with the column ((AbstractGridColumn) column).setGrid(this); @@ -1739,7 +1743,9 @@ public class Grid extends Composite implements int columnIndex = columns.indexOf(column); int visibleIndex = findVisibleColumnIndex(column); columns.remove(columnIndex); + header.removeColumn(columnIndex); + footer.removeColumn(columnIndex); // de-register column with grid ((AbstractGridColumn) column).setGrid(null); @@ -1991,6 +1997,25 @@ public class Grid extends Composite implements return null; } + /** + * Returns the header section of this grid. The default header contains a + * single row displaying the column captions. + * + * @return the header + */ + public GridHeader getHeader() { + return header; + } + + /** + * Returns the footer section of this grid. The default footer is empty. + * + * @return the footer + */ + public GridFooter getFooter() { + return footer; + } + /** * {@inheritDoc} *

diff --git a/client/src/com/vaadin/client/ui/grid/GridFooter.java b/client/src/com/vaadin/client/ui/grid/GridFooter.java new file mode 100644 index 0000000000..dc0f0054a2 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/GridFooter.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid; + +import java.util.Collections; +import java.util.List; + +/** + * Represents the footer section of a Grid. The footer is always empty. + * + * TODO Arbitrary number of footer rows (zero by default) + * + * TODO Merging footer cells + * + * TODO Widgets in cells + * + * TODO HTML in cells + * + * @since + * @author Vaadin Ltd + */ +public class GridFooter extends GridStaticSection { + + /** + * A single row in a grid Footer section. + * + */ + public static class FooterRow extends + GridStaticSection.StaticRow { + + @Override + protected FooterCell createCell() { + return new FooterCell(); + } + } + + /** + * A single cell in a grid Footer row. Has a textual caption. + * + */ + public static class FooterCell extends GridStaticSection.StaticCell { + } + + @Override + protected FooterRow createRow() { + return new FooterRow(); + } + + @Override + protected List createRowList() { + return Collections.emptyList(); + } +} diff --git a/client/src/com/vaadin/client/ui/grid/GridHeader.java b/client/src/com/vaadin/client/ui/grid/GridHeader.java index 023973c511..c23c848b8d 100644 --- a/client/src/com/vaadin/client/ui/grid/GridHeader.java +++ b/client/src/com/vaadin/client/ui/grid/GridHeader.java @@ -15,18 +15,15 @@ */ package com.vaadin.client.ui.grid; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import com.vaadin.client.ui.grid.renderers.TextRenderer; - /** * Represents the header section of a Grid. A header consists of a single header * row containing a header cell for each column. Each cell has a simple textual * caption. * - * TODO Arbitrary number of header rows (zero included) + * TODO Arbitrary number of header rows (zero included, one by default) * * TODO Merging header cells * @@ -39,67 +36,35 @@ import com.vaadin.client.ui.grid.renderers.TextRenderer; * @since * @author Vaadin Ltd */ -public class GridHeader { +public class GridHeader extends GridStaticSection { /** * A single row in a grid header section. * - * @since - * @author Vaadin Ltd */ - public static class HeaderRow { - - private List cells = new ArrayList(); - - private Renderer renderer = new TextRenderer(); - - public HeaderCell getCell(int index) { - return cells.get(index); - } - - protected void addCell(int index) { - cells.add(index, new HeaderCell()); - } - - protected void removeCell(int index) { - cells.remove(index); - } + public static class HeaderRow extends + GridStaticSection.StaticRow { - protected Renderer getRenderer() { - return renderer; + @Override + protected HeaderCell createCell() { + return new HeaderCell(); } } /** * A single cell in a grid header row. Has a textual caption. * - * @since - * @author Vaadin Ltd */ - public static class HeaderCell { - - private String text = ""; - - public void setText(String text) { - this.text = text; - } - - public String getText() { - return text; - } - } - - private List rows = Arrays.asList(new HeaderRow()); - - public HeaderRow getRow(int index) { - return rows.get(index); + public static class HeaderCell extends GridStaticSection.StaticCell { } - protected void addColumn(GridColumn column, int index) { - getRow(0).addCell(index); + @Override + protected HeaderRow createRow() { + return new HeaderRow(); } - protected void removeColumn(int index) { - getRow(0).removeCell(index); + @Override + protected List createRowList() { + return Arrays.asList(createRow()); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java new file mode 100644 index 0000000000..3273c2dfa2 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -0,0 +1,141 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid; + +import java.util.ArrayList; +import java.util.List; + +import com.vaadin.client.ui.grid.GridStaticSection.StaticRow; +import com.vaadin.client.ui.grid.renderers.TextRenderer; + +/** + * Abstract base class for Grid header and footer sections. + * + * @since + * @author Vaadin Ltd + * @param + * the type of the rows in the section + */ +abstract class GridStaticSection> { + + /** + * A header or footer cell. Has a simple textual caption. + * + * TODO HTML content + * + * TODO Widget content + */ + static class StaticCell { + + private String text = ""; + + /** + * Sets the text displayed in this cell. + * + * @param text + * a plain text caption + */ + public void setText(String text) { + this.text = text; + } + + /** + * Returns the text displayed in this cell. + * + * @return the plain text caption + */ + public String getText() { + return text; + } + } + + /** + * Abstract base class for Grid header and footer rows. + * + * @param + * the type of the cells in the row + */ + abstract static class StaticRow { + + private List cells = new ArrayList(); + + private Renderer renderer = new TextRenderer(); + + /** + * Returns the cell at the given position in this row. + * + * @param index + * the position of the cell + * @return the cell at the index + * @throws IndexOutOfBoundsException + * if the index is out of bounds + */ + public CELLTYPE getCell(int index) { + return cells.get(index); + } + + protected void addCell(int index) { + cells.add(index, createCell()); + } + + protected void removeCell(int index) { + cells.remove(index); + } + + protected Renderer getRenderer() { + return renderer; + } + + protected abstract CELLTYPE createCell(); + } + + private List rows = createRowList(); + + /** + * Returns the row at the given position in this section. + * + * @param index + * the position of the row + * @return the row at the index + * @throws IndexOutOfBoundsException + * if the index is out of bounds + */ + public ROWTYPE getRow(int index) { + return rows.get(index); + } + + protected List getRows() { + return rows; + } + + protected void addColumn(GridColumn column, int index) { + for (ROWTYPE row : getRows()) { + row.addCell(index); + } + } + + protected void removeColumn(int index) { + for (ROWTYPE row : getRows()) { + row.removeCell(index); + } + } + + protected List createRowList() { + return new ArrayList(); + } + + protected abstract ROWTYPE createRow(); +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java index a3c62e0303..cc48f11c69 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java @@ -71,6 +71,14 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { return headerCells; } + protected List getGridFooterRowCells() { + List footerCells = new ArrayList(); + for (int i = 0; i < getGridElement().getFooterCount(); ++i) { + footerCells.addAll(getGridElement().getFooterCells(i)); + } + return footerCells; + } + private Object executeScript(String script, WebElement element) { final WebDriver driver = getDriver(); if (driver instanceof JavascriptExecutor) { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java new file mode 100644 index 0000000000..e126994f34 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.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 static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Test; + +import com.vaadin.testbench.TestBenchElement; + +public class GridFooterTest extends GridBasicClientFeaturesTest { + + @Test + public void testFooterVisibility() throws Exception { + openTestURL(); + + // Footer should have zero rows by default + List cells = getGridFooterRowCells(); + assertEquals(0, cells.size()); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java index dfbb1679b0..716e3b30fc 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java @@ -26,11 +26,54 @@ import com.vaadin.testbench.TestBenchElement; public class GridHeaderTest extends GridBasicClientFeaturesTest { @Test - public void testHeaderVisible() throws Exception { + public void testHeaderVisibility() throws Exception { openTestURL(); - // Column headers should be visible + // Column headers should be visible by default List cells = getGridHeaderRowCells(); assertEquals(GridBasicFeatures.COLUMNS, cells.size()); } + + @Test + public void testHeaderCaptions() throws Exception { + openTestURL(); + + List cells = getGridHeaderRowCells(); + + int i = 0; + for (TestBenchElement cell : cells) { + assertText("Column " + i, cell); + i++; + } + } + + @Test + public void testHeadersWithInvisibleColumns() throws Exception { + openTestURL(); + + selectMenuPath("Component", "Columns", "Column 1", "Visible"); + selectMenuPath("Component", "Columns", "Column 3", "Visible"); + + List cells = getGridHeaderRowCells(); + assertEquals(GridBasicFeatures.COLUMNS - 2, cells.size()); + + assertText("Column 0", cells.get(0)); + assertText("Column 2", cells.get(1)); + assertText("Column 4", cells.get(2)); + + selectMenuPath("Component", "Columns", "Column 3", "Visible"); + + cells = getGridHeaderRowCells(); + assertEquals(GridBasicFeatures.COLUMNS - 1, cells.size()); + + assertText("Column 0", cells.get(0)); + assertText("Column 2", cells.get(1)); + assertText("Column 3", cells.get(2)); + assertText("Column 4", cells.get(3)); + } + + private static void assertText(String text, TestBenchElement e) { + // TBE.getText returns "" if the element is scrolled out of view + assertEquals(text, e.getAttribute("innerHTML")); + } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index 857ff14528..182a5bfa29 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -25,6 +25,7 @@ import com.vaadin.client.ui.grid.FlyweightCell; import com.vaadin.client.ui.grid.Grid; import com.vaadin.client.ui.grid.Grid.SelectionMode; import com.vaadin.client.ui.grid.GridColumn; +import com.vaadin.client.ui.grid.GridHeader.HeaderCell; import com.vaadin.client.ui.grid.Renderer; import com.vaadin.client.ui.grid.datasources.ListDataSource; import com.vaadin.client.ui.grid.renderers.DateRenderer; @@ -192,35 +193,61 @@ public class GridBasicClientFeatures extends }); } + // Set captions to column headers + + for (int i = 0; i < COLUMNS; ++i) { + HeaderCell cell = grid.getHeader().getRow(0).getCell(i); + cell.setText("Column " + i); + } + // // Populate the menu // + createStateMenu(); + createColumnsMenu(); + + grid.getElement().getStyle().setZIndex(0); + add(grid); + } + + private void createStateMenu() { + String[] selectionModePath = { "Component", "State", "Selection mode" }; + addMenuCommand("multi", new ScheduledCommand() { @Override public void execute() { grid.setSelectionMode(SelectionMode.MULTI); } - }, "Component", "State", "Selection mode"); + }, selectionModePath); addMenuCommand("single", new ScheduledCommand() { - @Override public void execute() { grid.setSelectionMode(SelectionMode.SINGLE); } - }, "Component", "State", "Selection mode"); + }, selectionModePath); addMenuCommand("none", new ScheduledCommand() { - @Override public void execute() { grid.setSelectionMode(SelectionMode.NONE); } - }, "Component", "State", "Selection mode"); + }, selectionModePath); + } - grid.getElement().getStyle().setZIndex(0); - add(grid); + private void createColumnsMenu() { + + for (int i = 0; i < COLUMNS; i++) { + final int index = i; + addMenuCommand("Visible", new ScheduledCommand() { + @Override + public void execute() { + grid.getColumn(index).setVisible( + !grid.getColumn(index).isVisible()); + } + }, "Component", "Columns", "Column " + i); + } } /** -- cgit v1.2.3 From aca2902c9cafcb02db19a0cdd42b1488786c0f56 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 15 Jul 2014 20:44:59 +0300 Subject: Client-side Grid header/footer rewrite: add add/remove rows support (#13334) Currently supported: * Adding and removal of header and footer rows * Header is single-row by default * Footer is zero-row by default * Text captions TODO: * Column spanning * HTML content * Widget content * Component content * Sorting/Indicators * Server side API * Shared state handling Change-Id: I54b5062f31e38e872ca64394dfa02f866a1af202 --- client/src/com/vaadin/client/ui/grid/Grid.java | 12 +- .../src/com/vaadin/client/ui/grid/GridFooter.java | 12 +- .../src/com/vaadin/client/ui/grid/GridHeader.java | 12 +- .../vaadin/client/ui/grid/GridStaticSection.java | 143 +++++++++++++++++++-- .../grid/basicfeatures/GridFooterTest.java | 52 +++++++- .../grid/basicfeatures/GridHeaderTest.java | 76 ++++++++--- .../grid/basicfeatures/GridStaticSectionTest.java | 52 ++++++++ .../client/grid/GridBasicClientFeatures.java | 89 ++++++++++++- 8 files changed, 382 insertions(+), 66 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 4465cd0070..18c1cbae01 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -45,7 +45,6 @@ import com.vaadin.client.Util; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.SubPartAware; -import com.vaadin.client.ui.grid.GridStaticSection.StaticRow; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.TextRenderer; import com.vaadin.client.ui.grid.renderers.WidgetRenderer; @@ -1311,7 +1310,8 @@ public class Grid extends Composite implements @Override public void update(Row row, Iterable cellsToUpdate) { - StaticRow gridRow = section.getRow(row.getRow()); + GridStaticSection.StaticRow gridRow = section.getRow(row + .getRow()); final List columnIndices = getVisibleColumnIndices(); @@ -1365,8 +1365,10 @@ public class Grid extends Composite implements escalator.getBody().setEscalatorUpdater(createBodyUpdater()); escalator.getFooter().setEscalatorUpdater(createFooterUpdater()); - refreshHeader(); - refreshFooter(); + header.setGrid(this); + header.appendRow(); + + footer.setGrid(this); setSelectionMode(SelectionMode.SINGLE); @@ -1574,7 +1576,7 @@ public class Grid extends Composite implements GridStaticSection section) { // Add or Remove rows on demand - int rowDiff = section.getRows().size() - rows.getRowCount(); + int rowDiff = section.getRowCount() - rows.getRowCount(); if (rowDiff > 0) { rows.insertRows(0, rowDiff); } else if (rowDiff < 0) { diff --git a/client/src/com/vaadin/client/ui/grid/GridFooter.java b/client/src/com/vaadin/client/ui/grid/GridFooter.java index dc0f0054a2..7f478f7d29 100644 --- a/client/src/com/vaadin/client/ui/grid/GridFooter.java +++ b/client/src/com/vaadin/client/ui/grid/GridFooter.java @@ -15,9 +15,6 @@ */ package com.vaadin.client.ui.grid; -import java.util.Collections; -import java.util.List; - /** * Represents the footer section of a Grid. The footer is always empty. * @@ -38,8 +35,7 @@ public class GridFooter extends GridStaticSection { * A single row in a grid Footer section. * */ - public static class FooterRow extends - GridStaticSection.StaticRow { + public class FooterRow extends GridStaticSection.StaticRow { @Override protected FooterCell createCell() { @@ -51,7 +47,7 @@ public class GridFooter extends GridStaticSection { * A single cell in a grid Footer row. Has a textual caption. * */ - public static class FooterCell extends GridStaticSection.StaticCell { + public class FooterCell extends GridStaticSection.StaticCell { } @Override @@ -60,7 +56,7 @@ public class GridFooter extends GridStaticSection { } @Override - protected List createRowList() { - return Collections.emptyList(); + protected void refreshGrid() { + getGrid().refreshFooter(); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridHeader.java b/client/src/com/vaadin/client/ui/grid/GridHeader.java index c23c848b8d..a2207c49c7 100644 --- a/client/src/com/vaadin/client/ui/grid/GridHeader.java +++ b/client/src/com/vaadin/client/ui/grid/GridHeader.java @@ -15,9 +15,6 @@ */ package com.vaadin.client.ui.grid; -import java.util.Arrays; -import java.util.List; - /** * Represents the header section of a Grid. A header consists of a single header * row containing a header cell for each column. Each cell has a simple textual @@ -42,8 +39,7 @@ public class GridHeader extends GridStaticSection { * A single row in a grid header section. * */ - public static class HeaderRow extends - GridStaticSection.StaticRow { + public class HeaderRow extends GridStaticSection.StaticRow { @Override protected HeaderCell createCell() { @@ -55,7 +51,7 @@ public class GridHeader extends GridStaticSection { * A single cell in a grid header row. Has a textual caption. * */ - public static class HeaderCell extends GridStaticSection.StaticCell { + public class HeaderCell extends GridStaticSection.StaticCell { } @Override @@ -64,7 +60,7 @@ public class GridHeader extends GridStaticSection { } @Override - protected List createRowList() { - return Arrays.asList(createRow()); + protected void refreshGrid() { + getGrid().refreshHeader(); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index 3273c2dfa2..5b4523ab76 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -18,7 +18,6 @@ package com.vaadin.client.ui.grid; import java.util.ArrayList; import java.util.List; -import com.vaadin.client.ui.grid.GridStaticSection.StaticRow; import com.vaadin.client.ui.grid.renderers.TextRenderer; /** @@ -29,7 +28,7 @@ import com.vaadin.client.ui.grid.renderers.TextRenderer; * @param * the type of the rows in the section */ -abstract class GridStaticSection> { +abstract class GridStaticSection> { /** * A header or footer cell. Has a simple textual caption. @@ -42,6 +41,8 @@ abstract class GridStaticSection> { private String text = ""; + private GridStaticSection section; + /** * Sets the text displayed in this cell. * @@ -50,6 +51,7 @@ abstract class GridStaticSection> { */ public void setText(String text) { this.text = text; + section.refreshGrid(); } /** @@ -60,6 +62,16 @@ abstract class GridStaticSection> { public String getText() { return text; } + + protected GridStaticSection getSection() { + assert section != null; + return section; + } + + protected void setSection(GridStaticSection section) { + this.section = section; + } + } /** @@ -74,6 +86,8 @@ abstract class GridStaticSection> { private Renderer renderer = new TextRenderer(); + private GridStaticSection section; + /** * Returns the cell at the given position in this row. * @@ -88,7 +102,9 @@ abstract class GridStaticSection> { } protected void addCell(int index) { - cells.add(index, createCell()); + CELLTYPE cell = createCell(); + cell.setSection(getSection()); + cells.add(index, cell); } protected void removeCell(int index) { @@ -100,16 +116,109 @@ abstract class GridStaticSection> { } protected abstract CELLTYPE createCell(); + + protected GridStaticSection getSection() { + return section; + } + + protected void setSection(GridStaticSection section) { + this.section = section; + } + } + + private Grid grid; + + private List rows = new ArrayList(); + + /** + * Creates and returns a new instance of the row type. + * + * @return the created row + */ + protected abstract ROWTYPE createRow(); + + /** + * Informs the grid that this section should be re-rendered. + */ + protected abstract void refreshGrid(); + + /** + * Inserts a new row at the given position. + * + * @param index + * the position at which to insert the row + * @return the new row + * + * @throws IndexOutOfBoundsException + * if the index is out of bounds + */ + public ROWTYPE addRow(int index) { + ROWTYPE row = createRow(); + row.setSection(this); + for (int i = 0; i < getGrid().getColumnCount(); ++i) { + row.addCell(i); + } + rows.add(index, row); + refreshGrid(); + return row; + } + + /** + * Adds a new row at the top of this section. + * + * @return the new row + */ + public ROWTYPE prependRow() { + return addRow(0); + } + + /** + * Adds a new row at the bottom of this section. + * + * @return the new row + */ + public ROWTYPE appendRow() { + return addRow(rows.size()); + } + + /** + * Removes the row at the given position. + * + * @param index + * the position of the row + * + * @throws IndexOutOfBoundsException + * if the index is out of bounds + */ + public void removeRow(int index) { + rows.remove(index); + refreshGrid(); } - private List rows = createRowList(); + /** + * Removes the given row from the section. + * + * @param row + * the row to be removed + * + * @throws IllegalArgumentException + * if the row does not exist in this section + */ + public void removeRow(ROWTYPE row) { + if (!rows.remove(row)) { + throw new IllegalArgumentException( + "Section does not contain the given row"); + } + refreshGrid(); + } /** - * Returns the row at the given position in this section. + * Returns the row at the given position. * * @param index * the position of the row - * @return the row at the index + * @return the row with the given index + * * @throws IndexOutOfBoundsException * if the index is out of bounds */ @@ -117,25 +226,37 @@ abstract class GridStaticSection> { return rows.get(index); } + /** + * Returns the number of rows in this section. + * + * @return the number of rows + */ + public int getRowCount() { + return rows.size(); + } + protected List getRows() { return rows; } protected void addColumn(GridColumn column, int index) { - for (ROWTYPE row : getRows()) { + for (ROWTYPE row : rows) { row.addCell(index); } } protected void removeColumn(int index) { - for (ROWTYPE row : getRows()) { + for (ROWTYPE row : rows) { row.removeCell(index); } } - protected List createRowList() { - return new ArrayList(); + protected void setGrid(Grid grid) { + this.grid = grid; } - protected abstract ROWTYPE createRow(); + protected Grid getGrid() { + assert grid != null; + return grid; + } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java index e126994f34..80110ddc81 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java @@ -17,20 +17,58 @@ package com.vaadin.tests.components.grid.basicfeatures; import static org.junit.Assert.assertEquals; -import java.util.List; - import org.junit.Test; -import com.vaadin.testbench.TestBenchElement; - -public class GridFooterTest extends GridBasicClientFeaturesTest { +public class GridFooterTest extends GridStaticSectionTest { @Test public void testFooterVisibility() throws Exception { openTestURL(); // Footer should have zero rows by default - List cells = getGridFooterRowCells(); - assertEquals(0, cells.size()); + assertEquals(0, getGridFooterRowCells().size()); + } + + @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); + } + + private void assertFooterCount(int count) { + assertEquals("footer count", count, getGridElement().getFooterCount()); } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java index 716e3b30fc..c1bc4cdd73 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java @@ -23,28 +23,21 @@ import org.junit.Test; import com.vaadin.testbench.TestBenchElement; -public class GridHeaderTest extends GridBasicClientFeaturesTest { +public class GridHeaderTest extends GridStaticSectionTest { @Test public void testHeaderVisibility() throws Exception { openTestURL(); // Column headers should be visible by default - List cells = getGridHeaderRowCells(); - assertEquals(GridBasicFeatures.COLUMNS, cells.size()); + assertEquals(GridBasicFeatures.COLUMNS, getGridHeaderRowCells().size()); } @Test public void testHeaderCaptions() throws Exception { openTestURL(); - List cells = getGridHeaderRowCells(); - - int i = 0; - for (TestBenchElement cell : cells) { - assertText("Column " + i, cell); - i++; - } + assertHeaderTexts(0, 0); } @Test @@ -57,23 +50,66 @@ public class GridHeaderTest extends GridBasicClientFeaturesTest { List cells = getGridHeaderRowCells(); assertEquals(GridBasicFeatures.COLUMNS - 2, cells.size()); - assertText("Column 0", cells.get(0)); - assertText("Column 2", cells.get(1)); - assertText("Column 4", cells.get(2)); + assertText("Header (0,0)", cells.get(0)); + assertText("Header (0,2)", cells.get(1)); + assertText("Header (0,4)", cells.get(2)); selectMenuPath("Component", "Columns", "Column 3", "Visible"); cells = getGridHeaderRowCells(); assertEquals(GridBasicFeatures.COLUMNS - 1, cells.size()); - assertText("Column 0", cells.get(0)); - assertText("Column 2", cells.get(1)); - assertText("Column 3", cells.get(2)); - assertText("Column 4", cells.get(3)); + assertText("Header (0,0)", cells.get(0)); + assertText("Header (0,2)", cells.get(1)); + assertText("Header (0,3)", cells.get(2)); + assertText("Header (0,4)", 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); } - private static void assertText(String text, TestBenchElement e) { - // TBE.getText returns "" if the element is scrolled out of view - assertEquals(text, e.getAttribute("innerHTML")); + private void assertHeaderCount(int count) { + assertEquals("header count", count, getGridElement().getHeaderCount()); } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java new file mode 100644 index 0000000000..8f6739e16d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java @@ -0,0 +1,52 @@ +/* + * 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 com.vaadin.testbench.TestBenchElement; + +/** + * 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)) { + assertText(String.format("Header (%d,%d)", 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)) { + assertText(String.format("Footer (%d,%d)", 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")); + } +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index 182a5bfa29..8564b149d8 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -25,7 +25,10 @@ import com.vaadin.client.ui.grid.FlyweightCell; import com.vaadin.client.ui.grid.Grid; import com.vaadin.client.ui.grid.Grid.SelectionMode; import com.vaadin.client.ui.grid.GridColumn; -import com.vaadin.client.ui.grid.GridHeader.HeaderCell; +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.renderers.DateRenderer; @@ -193,12 +196,7 @@ public class GridBasicClientFeatures extends }); } - // Set captions to column headers - - for (int i = 0; i < COLUMNS; ++i) { - HeaderCell cell = grid.getHeader().getRow(0).getCell(i); - cell.setText("Column " + i); - } + setHeaderTexts(grid.getHeader().getRow(0)); // // Populate the menu @@ -206,6 +204,8 @@ public class GridBasicClientFeatures extends createStateMenu(); createColumnsMenu(); + createHeaderMenu(); + createFooterMenu(); grid.getElement().getStyle().setZIndex(0); add(grid); @@ -250,6 +250,81 @@ public class GridBasicClientFeatures extends } } + private int headerCounter = 0; + private int footerCounter = 0; + + private void setHeaderTexts(HeaderRow row) { + for (int i = 0; i < COLUMNS; ++i) { + row.getCell(i).setText("Header (" + headerCounter + "," + i + ")"); + } + headerCounter++; + } + + private void setFooterTexts(FooterRow row) { + for (int i = 0; i < COLUMNS; ++i) { + row.getCell(i).setText("Footer (" + footerCounter + "," + i + ")"); + } + footerCounter++; + } + + private void createHeaderMenu() { + final GridHeader header = grid.getHeader(); + addMenuCommand("Prepend row", new ScheduledCommand() { + @Override + public void execute() { + setHeaderTexts(header.prependRow()); + } + }, "Component", "Header"); + addMenuCommand("Append row", new ScheduledCommand() { + @Override + public void execute() { + setHeaderTexts(header.appendRow()); + } + }, "Component", "Header"); + addMenuCommand("Remove top row", new ScheduledCommand() { + @Override + public void execute() { + header.removeRow(0); + } + }, "Component", "Header"); + addMenuCommand("Remove bottom row", new ScheduledCommand() { + @Override + public void execute() { + header.removeRow(header.getRowCount() - 1); + } + }, "Component", "Header"); + } + + private void createFooterMenu() { + + final GridFooter footer = grid.getFooter(); + + addMenuCommand("Prepend row", new ScheduledCommand() { + @Override + public void execute() { + setFooterTexts(footer.prependRow()); + } + }, "Component", "Footer"); + addMenuCommand("Append row", new ScheduledCommand() { + @Override + public void execute() { + setFooterTexts(footer.appendRow()); + } + }, "Component", "Footer"); + addMenuCommand("Remove top row", new ScheduledCommand() { + @Override + public void execute() { + footer.removeRow(0); + } + }, "Component", "Footer"); + addMenuCommand("Remove bottom row", new ScheduledCommand() { + @Override + public void execute() { + footer.removeRow(footer.getRowCount() - 1); + } + }, "Component", "Footer"); + } + /** * Creates a a renderer for a {@link Renderers} */ -- cgit v1.2.3 From a08d6a34fc7a89c1bad74047bfe2fd38a585e409 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 17 Jul 2014 16:43:25 +0300 Subject: Implement keyboard navigation between containers (#13334) Change-Id: I1592582eb20d46bac6ef6f5a6e995a6b3a73098b --- client/src/com/vaadin/client/ui/grid/Grid.java | 94 +++++++++++++++++++--- .../basicfeatures/GridKeyboardNavigationTest.java | 29 +++++-- 2 files changed, 107 insertions(+), 16 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 18c1cbae01..866ba611b3 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -265,16 +265,10 @@ public class Grid extends Composite implements * Handle events that can change the currently active cell. */ public void handleNavigationEvent(Event event, Cell cell) { - if (event.getType().equals(BrowserEvents.CLICK) - && event.getButton() == NativeEvent.BUTTON_LEFT - && cell != null) { + if (event.getType().equals(BrowserEvents.CLICK) && cell != null) { setActiveCell(cell); getElement().focus(); } else if (event.getType().equals(BrowserEvents.KEYDOWN)) { - int keyCode = event.getKeyCode(); - if (keyCode == 0) { - keyCode = event.getCharCode(); - } int newRow = activeRow; int newColumn = activeColumn; RowContainer newContainer = container; @@ -292,12 +286,36 @@ public class Grid extends Composite implements case KeyCodes.KEY_LEFT: newColumn -= 1; break; + default: + return; } if (newRow < 0) { - newRow = 0; + newContainer = getPreviousContainer(newContainer); + + if (newContainer == container) { + newRow = 0; + } else if (newContainer == escalator.getBody()) { + newRow = getLastVisibleRowIndex(); + } else { + newRow = newContainer.getRowCount() - 1; + } } else if (newRow >= container.getRowCount()) { - newRow = container.getRowCount() - 1; + newContainer = getNextContainer(newContainer); + + if (newContainer == container) { + newRow = container.getRowCount() - 1; + } else if (newContainer == escalator.getBody()) { + newRow = getFirstVisibleRowIndex(); + } else { + newRow = 0; + } + } + + if (newContainer.getRowCount() == 0) { + // There are no rows in the container. Can't change the + // active cell. + return; } if (newColumn < 0) { @@ -306,11 +324,69 @@ public class Grid extends Composite implements newColumn = getColumnCount() - 1; } + event.preventDefault(); + event.stopPropagation(); + setActiveCell(newRow, newColumn, newContainer); } } + private int getLastVisibleRowIndex() { + int lastRowIndex = escalator.getVisibleRowRange().getEnd(); + int footerTop = escalator.getFooter().getElement().getAbsoluteTop(); + Element lastRow; + + do { + lastRow = escalator.getBody().getRowElement(--lastRowIndex); + } while (lastRow.getAbsoluteBottom() > footerTop); + + return lastRowIndex; + } + + private int getFirstVisibleRowIndex() { + int firstRowIndex = escalator.getVisibleRowRange().getStart(); + int headerBottom = escalator.getHeader().getElement() + .getAbsoluteBottom(); + Element firstRow = escalator.getBody().getRowElement(firstRowIndex); + + while (firstRow.getAbsoluteTop() < headerBottom) { + firstRow = escalator.getBody().getRowElement(++firstRowIndex); + } + + return firstRowIndex; + } + + private RowContainer getPreviousContainer(RowContainer current) { + if (current == escalator.getFooter()) { + current = escalator.getBody(); + } else if (current == escalator.getBody()) { + current = escalator.getHeader(); + } else { + return current; + } + + if (current.getRowCount() == 0) { + return getPreviousContainer(current); + } + return current; + } + + private RowContainer getNextContainer(RowContainer current) { + if (current == escalator.getHeader()) { + current = escalator.getBody(); + } else if (current == escalator.getBody()) { + current = escalator.getFooter(); + } else { + return current; + } + + if (current.getRowCount() == 0) { + return getNextContainer(current); + } + return current; + } + private void refreshRow(int row) { container.refreshRows(row, 1); } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java index 465fdedad6..4c7e7c6365 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java @@ -18,9 +18,6 @@ package com.vaadin.tests.components.grid.basicfeatures; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import java.io.IOException; - -import org.junit.Ignore; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.Keys; @@ -89,18 +86,36 @@ public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { } @Test - @Ignore("This feature is still on the TODO list") - public void testNavigateFromHeaderToBody() throws IOException { + public void testNavigateFromHeaderToBody() { openTestURL(); GridElement grid = getGridElement(); grid.scrollToRow(300); - grid.getHeaderCell(0, 7).click(); + 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 282, 7 is not active", grid.getCell(282, 7) + assertTrue("Body cell 280, 7 is not active", grid.getCell(280, 7) + .isActive()); + } + + @Test + public void testNavigationFromFooterToBody() { + openTestURL(); + + selectMenuPath("Component", "Footers", "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()); } } -- cgit v1.2.3 From 0bbd14486e3839c60e1e59f12dc959b133b6ed05 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Fri, 18 Jul 2014 11:18:58 +0300 Subject: Implement Tab navigation for Grid (#13334) Change-Id: If2c1f3db23247355439360def983dba714979a48 --- .../src/com/vaadin/client/ui/grid/Escalator.java | 2 + client/src/com/vaadin/client/ui/grid/Grid.java | 32 +++++++++++++- .../grid/basicfeatures/GridBasicFeaturesTest.java | 10 +++++ .../basicfeatures/GridKeyboardNavigationTest.java | 51 ++++++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index 0a237f3fca..df564be937 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -3938,9 +3938,11 @@ public class Escalator extends Widget { setElement(root); root.appendChild(verticalScrollbar.getElement()); + verticalScrollbar.getElement().setTabIndex(-1); verticalScrollbar.setScrollbarThickness(Util.getNativeScrollbarSize()); root.appendChild(horizontalScrollbar.getElement()); + horizontalScrollbar.getElement().setTabIndex(-1); horizontalScrollbar .setScrollbarThickness(Util.getNativeScrollbarSize()); horizontalScrollbar diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 866ba611b3..833c59d08b 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -106,6 +106,9 @@ public class Grid extends Composite implements private RowContainer container = escalator.getBody(); private int activeRow = 0; private int activeColumn = 0; + private int lastActiveBodyRow = 0; + private int lastActiveHeaderRow = 0; + private int lastActiveFooterRow = 0; private Element cellWithActiveStyle = null; private Element rowWithActiveStyle = null; @@ -227,6 +230,14 @@ public class Grid extends Composite implements RowContainer oldContainer = this.container; this.container = container; + if (oldContainer == escalator.getBody()) { + lastActiveBodyRow = oldRow; + } else if (oldContainer == escalator.getHeader()) { + lastActiveHeaderRow = oldRow; + } else { + lastActiveFooterRow = oldRow; + } + if (oldColumn != activeColumn) { refreshHeader(); refreshFooter(); @@ -286,11 +297,30 @@ public class Grid extends Composite implements case KeyCodes.KEY_LEFT: newColumn -= 1; break; + case KeyCodes.KEY_TAB: + if (event.getShiftKey()) { + newContainer = getPreviousContainer(container); + } else { + newContainer = getNextContainer(container); + } + + if (newContainer == container) { + return; + } + break; default: return; } - if (newRow < 0) { + if (newContainer != container) { + if (newContainer == escalator.getBody()) { + newRow = lastActiveBodyRow; + } else if (newContainer == escalator.getHeader()) { + newRow = lastActiveHeaderRow; + } else { + newRow = lastActiveFooterRow; + } + } else if (newRow < 0) { newContainer = getPreviousContainer(newContainer); if (newContainer == container) { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java index cc48f11c69..94d9766f78 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java @@ -23,6 +23,7 @@ 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; @@ -32,6 +33,15 @@ 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; diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java index 4c7e7c6365..4c26124a51 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java @@ -118,4 +118,55 @@ public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { 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", "Footers", "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()); + } } -- cgit v1.2.3 From 1726ce75310c6341007b35ba5b93e25466e8531b Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Fri, 18 Jul 2014 15:33:55 +0300 Subject: Client-side Grid header/footer rewrite: add section setVisible (#13334) Currently supported: * Adding and removal of header and footer rows * Header is single-row by default * Footer is zero-row by default * Text captions * Showing and hiding the whole header or footer TODO: * Column spanning * HTML content * Widget content * Component content * Sorting/Indicators * Server side API * Shared state handling Change-Id: I9708f6f5dd7e9212e9ba5f1e462b55ca619c3df0 --- client/src/com/vaadin/client/ui/grid/Grid.java | 2 +- .../vaadin/client/ui/grid/GridStaticSection.java | 26 +++++++++++++++++ .../grid/basicfeatures/GridFooterTest.java | 21 +++++++++++-- .../grid/basicfeatures/GridHeaderTest.java | 21 +++++++++++-- .../client/grid/GridBasicClientFeatures.java | 34 ++++++++++++++++------ 5 files changed, 90 insertions(+), 14 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 833c59d08b..403b0d1e3f 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -1682,7 +1682,7 @@ public class Grid extends Composite implements GridStaticSection section) { // Add or Remove rows on demand - int rowDiff = section.getRowCount() - rows.getRowCount(); + int rowDiff = section.getVisibleRowCount() - rows.getRowCount(); if (rowDiff > 0) { rows.insertRows(0, rowDiff); } else if (rowDiff < 0) { diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index 5b4523ab76..f455acc92e 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -130,6 +130,8 @@ abstract class GridStaticSection> private List rows = new ArrayList(); + private boolean visible = true; + /** * Creates and returns a new instance of the row type. * @@ -142,6 +144,26 @@ abstract class GridStaticSection> */ protected abstract void refreshGrid(); + /** + * Sets the visibility of the whole section. + * + * @param visible + * true to show this section, false to hide + */ + public void setVisible(boolean visible) { + this.visible = visible; + refreshGrid(); + } + + /** + * Returns the visibility of this section. + * + * @return true if visible, false otherwise. + */ + public boolean isVisible() { + return visible; + } + /** * Inserts a new row at the given position. * @@ -239,6 +261,10 @@ abstract class GridStaticSection> return rows; } + protected int getVisibleRowCount() { + return isVisible() ? getRowCount() : 0; + } + protected void addColumn(GridColumn column, int index) { for (ROWTYPE row : rows) { row.addCell(index); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java index 80110ddc81..f7dd85e3c3 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java @@ -22,11 +22,28 @@ import org.junit.Test; public class GridFooterTest extends GridStaticSectionTest { @Test - public void testFooterVisibility() throws Exception { + public void testDefaultFooter() { openTestURL(); // Footer should have zero rows by default - assertEquals(0, getGridFooterRowCells().size()); + 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 diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java index c1bc4cdd73..2ced9e16d4 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java @@ -25,12 +25,29 @@ import com.vaadin.testbench.TestBenchElement; public class GridHeaderTest extends GridStaticSectionTest { + @Test + public void testDefaultHeader() throws Exception { + openTestURL(); + + assertHeaderCount(1); + assertHeaderTexts(0, 0); + } + @Test public void testHeaderVisibility() throws Exception { openTestURL(); - // Column headers should be visible by default - assertEquals(GridBasicFeatures.COLUMNS, getGridHeaderRowCells().size()); + selectMenuPath("Component", "Header", "Visible"); + + assertHeaderCount(0); + + selectMenuPath("Component", "Header", "Append row"); + + assertHeaderCount(0); + + selectMenuPath("Component", "Header", "Visible"); + + assertHeaderCount(2); } @Test diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index 8564b149d8..21d65d56ac 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -269,60 +269,76 @@ public class GridBasicClientFeatures extends 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("Prepend row", new ScheduledCommand() { @Override public void execute() { setHeaderTexts(header.prependRow()); } - }, "Component", "Header"); + }, menuPath); addMenuCommand("Append row", new ScheduledCommand() { @Override public void execute() { setHeaderTexts(header.appendRow()); } - }, "Component", "Header"); + }, menuPath); addMenuCommand("Remove top row", new ScheduledCommand() { @Override public void execute() { header.removeRow(0); } - }, "Component", "Header"); + }, menuPath); addMenuCommand("Remove bottom row", new ScheduledCommand() { @Override public void execute() { header.removeRow(header.getRowCount() - 1); } - }, "Component", "Header"); + }, 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() { setFooterTexts(footer.prependRow()); } - }, "Component", "Footer"); + }, menuPath); addMenuCommand("Append row", new ScheduledCommand() { @Override public void execute() { setFooterTexts(footer.appendRow()); } - }, "Component", "Footer"); + }, menuPath); addMenuCommand("Remove top row", new ScheduledCommand() { @Override public void execute() { footer.removeRow(0); } - }, "Component", "Footer"); + }, menuPath); addMenuCommand("Remove bottom row", new ScheduledCommand() { @Override public void execute() { footer.removeRow(footer.getRowCount() - 1); } - }, "Component", "Footer"); + }, menuPath); } /** -- cgit v1.2.3 From 6f5d9104a68641c143d11c5a1376ba728b8085cd Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 23 Jul 2014 11:27:38 +0300 Subject: Improve GridBasicClientFeaturesTest menu handling on some browsers Change-Id: Ie044d4872a6f3dbed11a7baad7c5e23e603103e5 --- .../components/grid/basicfeatures/GridBasicClientFeaturesTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java index 95b45b262e..559457ea1c 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java @@ -16,6 +16,7 @@ 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; @@ -45,7 +46,9 @@ public abstract class GridBasicClientFeaturesTest extends GridBasicFeaturesTest @Override protected void selectMenu(String menuCaption) { WebElement menuElement = getMenuElement(menuCaption); - new Actions(getDriver()).moveToElement(menuElement).perform(); + Dimension size = menuElement.getSize(); + new Actions(getDriver()).moveToElement(menuElement, size.width - 10, + size.height / 2).perform(); } private WebElement getMenuElement(String menuCaption) { @@ -59,6 +62,7 @@ public abstract class GridBasicClientFeaturesTest extends GridBasicFeaturesTest .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( -- cgit v1.2.3 From 7b749fb90f159ce285bc562a17293fbcd0d97400 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 23 Jul 2014 14:05:29 +0300 Subject: Add minimal Header/Footer visibility support to GridConnector (#13334) Change-Id: If1bc760d7237d77217fa40a6d91a43d6111e956a --- client/src/com/vaadin/client/ui/grid/GridConnector.java | 9 +++++---- .../grid/basicfeatures/GridKeyboardNavigationTest.java | 6 ++---- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index ca66ccc3d5..a2563488d3 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -262,6 +262,9 @@ public class GridConnector extends AbstractComponentConnector { getWidget().addSelectionChangeHandler(internalSelectionChangeHandler); + // TODO: Remove this workaround once we have header/footer communication + getWidget().getFooter().appendRow(); + getWidget().addSortHandler(new SortEventHandler() { @Override public void sort(SortEvent event) { @@ -320,14 +323,12 @@ public class GridConnector extends AbstractComponentConnector { // Header if (stateChangeEvent.hasPropertyChanged("columnHeadersVisible")) { - getWidget() - .setColumnHeadersVisible(getState().columnHeadersVisible); + getWidget().getHeader().setVisible(getState().columnHeadersVisible); } // Footer if (stateChangeEvent.hasPropertyChanged("columnFootersVisible")) { - getWidget() - .setColumnFootersVisible(getState().columnFootersVisible); + getWidget().getFooter().setVisible(getState().columnFootersVisible); } // Column row groups diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java index 4c26124a51..805213027e 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java @@ -70,18 +70,16 @@ public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { assertTrue("Body cell 1, 1 is not active after keyboard navigation.", grid.getCell(1, 1).isActive()); - Actions manyClicks = new Actions(getDriver()); int i; for (i = 1; i < 40; ++i) { - manyClicks.sendKeys(Keys.ARROW_DOWN); + new Actions(getDriver()).sendKeys(Keys.ARROW_DOWN).perform(); } - manyClicks.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) + assertTrue("Body cell " + i + ", 1 is not active", grid.getCell(i, 1) .isActive()); } -- cgit v1.2.3 From cfad6d54de44fead836ec9355bbc77c06fa26a40 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 16 Jul 2014 11:16:38 +0300 Subject: Client-side Grid header/footer rewrite: add default header support (#13334) Currently supported: * Adding and removal of header and footer rows * Header is single-row by default * Footer is zero-row by default * Text captions * Showing and hiding the whole header or footer * Default header rows for sorting UI TODO: * Column spanning * HTML content * Widget content * Component content * Server side API * Shared state handling Change-Id: I3d6a2b75fad87780f83238ab792bbbcfe99a48fd --- client/src/com/vaadin/client/ui/grid/Grid.java | 74 +++++++++++++--------- .../com/vaadin/client/ui/grid/GridConnector.java | 5 ++ .../src/com/vaadin/client/ui/grid/GridHeader.java | 73 +++++++++++++++++++++ .../vaadin/client/ui/grid/GridStaticSection.java | 9 ++- server/src/com/vaadin/ui/components/grid/Grid.java | 7 +- .../shared/ui/grid/GridStaticSectionState.java | 2 + .../grid/basicfeatures/GridHeaderTest.java | 38 +++++++++++ .../client/grid/GridBasicClientFeatures.java | 30 +++++++++ 8 files changed, 206 insertions(+), 32 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 403b0d1e3f..ff75417c12 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -45,6 +45,7 @@ import com.vaadin.client.Util; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.SubPartAware; +import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.TextRenderer; import com.vaadin.client.ui.grid.renderers.WidgetRenderer; @@ -616,6 +617,13 @@ public class Grid extends Composite implements protected abstract SelectionModel createModel(); } + class SortableColumnHeaderRenderer extends + AbstractGridColumn.SortableColumnHeaderRenderer { + SortableColumnHeaderRenderer(Renderer cellRenderer) { + super(Grid.this, cellRenderer); + } + } + /** * Base class for grid columns internally used by the Grid. The user should * use {@link GridColumn} when creating new columns. @@ -633,9 +641,11 @@ public class Grid extends Composite implements * * FIXME Currently assumes multisorting */ - private class SortableColumnHeaderRenderer extends + static class SortableColumnHeaderRenderer extends ComplexRenderer { + private Grid grid; + /** * Delay before a long tap action is triggered. Number in * milliseconds. @@ -658,7 +668,8 @@ public class Grid extends Composite implements @Override public void run() { - SortOrder sortingOrder = getSortingOrder(); + SortOrder sortingOrder = getSortingOrder(grid + .getColumnFromVisibleIndex(cell.getColumn())); if (sortingOrder == null) { /* * No previous sorting, sort Ascending @@ -697,7 +708,9 @@ public class Grid extends Composite implements * @param cellRenderer * The actual cell renderer */ - public SortableColumnHeaderRenderer(Renderer cellRenderer) { + public SortableColumnHeaderRenderer(Grid grid, + Renderer cellRenderer) { + this.grid = grid; this.cellRenderer = cellRenderer; } @@ -715,9 +728,11 @@ public class Grid extends Composite implements * this is fixed. */ if (grid != null) { - SortOrder sortingOrder = getSortingOrder(); + GridColumn column = grid + .getColumnFromVisibleIndex(cell.getColumn()); + SortOrder sortingOrder = getSortingOrder(column); Element cellElement = cell.getElement(); - if (grid.getColumn(cell.getColumn()).isSortable()) { + if (column.isSortable()) { if (sortingOrder != null) { if (SortDirection.ASCENDING == sortingOrder .getDirection()) { @@ -836,6 +851,18 @@ public class Grid extends Composite implements } + protected void removeFromRow(HeaderRow row) { + row.setRenderer(new Renderer() { + @Override + public void render(FlyweightCell cell, String data) { + cleanup(cell); + } + }); + grid.refreshHeader(); + row.setRenderer(cellRenderer); + grid.refreshHeader(); + } + /** * Sorts the column in a direction */ @@ -844,13 +871,14 @@ public class Grid extends Composite implements TableCellElement th = TableCellElement.as(cell.getElement()); // Apply primary sorting on clicked column - GridColumn columnInstance = getColumnInstance(); + GridColumn columnInstance = grid + .getColumnFromVisibleIndex(cell.getColumn()); Sort sorting = Sort.by(columnInstance, direction); // Re-apply old sorting to the sort order if (multisort) { for (SortOrder order : grid.getSortOrder()) { - if (order.getColumn() != AbstractGridColumn.this) { + if (order.getColumn() != columnInstance) { sorting = sorting.then(order.getColumn(), order.getDirection()); } @@ -861,24 +889,12 @@ public class Grid extends Composite implements grid.sort(sorting); } - /** - * Resolves a GridColumn out of a AbstractGridColumn - */ - private GridColumn getColumnInstance() { - for (GridColumn column : grid.getColumns()) { - if (column == AbstractGridColumn.this) { - return (GridColumn) column; - } - } - return null; - } - /** * Finds the sorting order for this column */ - private SortOrder getSortingOrder() { + private SortOrder getSortingOrder(GridColumn column) { for (SortOrder order : grid.getSortOrder()) { - if (order.getColumn() == AbstractGridColumn.this) { + if (order.getColumn() == column) { return order; } } @@ -922,8 +938,7 @@ public class Grid extends Composite implements * Renderer for rendering the header cell value into the cell */ @Deprecated - private Renderer headerRenderer = new SortableColumnHeaderRenderer( - new TextRenderer()); + private Renderer headerRenderer = new TextRenderer(); /** * Renderer for rendering the footer cell value into the cell @@ -964,8 +979,7 @@ public class Grid extends Composite implements throw new IllegalArgumentException("Renderer cannot be null."); } - this.headerRenderer = new SortableColumnHeaderRenderer( - headerRenderer); + this.headerRenderer = headerRenderer; this.footerRenderer = footerRenderer; } @@ -1016,7 +1030,7 @@ public class Grid extends Composite implements if (renderer == null) { throw new IllegalArgumentException("Renderer cannot be null."); } - headerRenderer = new SortableColumnHeaderRenderer(headerRenderer); + this.headerRenderer = headerRenderer; if (grid != null) { grid.refreshHeader(); } @@ -1472,7 +1486,8 @@ public class Grid extends Composite implements escalator.getFooter().setEscalatorUpdater(createFooterUpdater()); header.setGrid(this); - header.appendRow(); + HeaderRow defaultRow = header.appendRow(); + header.setDefaultRow(defaultRow); footer.setGrid(this); @@ -2470,13 +2485,14 @@ public class Grid extends Composite implements if (container != null) { cell = container.getCell(e); if (cell != null) { + // FIXME getFromVisibleIndex??? GridColumn gridColumn = columns.get(cell.getColumn()); Renderer renderer; if (container == escalator.getHeader()) { - renderer = gridColumn.getHeaderRenderer(); + renderer = header.getRow(cell.getRow()).getRenderer(); } else if (container == escalator.getFooter()) { - renderer = gridColumn.getFooterRenderer(); + renderer = footer.getRow(cell.getRow()).getRenderer(); } else { renderer = gridColumn.getRenderer(); } diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 67f4dc4045..3c7629a60d 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -36,6 +36,7 @@ import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.data.DataSource.RowHandle; import com.vaadin.client.data.RpcDataSourceConnector.RpcDataSource; import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.GridStaticSection.StaticRow; import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; import com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel; @@ -368,6 +369,10 @@ public class GridConnector extends AbstractComponentConnector { for (CellState cellState : rowState.cells) { row.getCell(i++).setText(cellState.text); } + + if (section instanceof GridHeader && rowState.defaultRow) { + ((GridHeader) section).setDefaultRow((HeaderRow) row); + } } section.setVisible(state.visible); diff --git a/client/src/com/vaadin/client/ui/grid/GridHeader.java b/client/src/com/vaadin/client/ui/grid/GridHeader.java index a2207c49c7..c5b0febeca 100644 --- a/client/src/com/vaadin/client/ui/grid/GridHeader.java +++ b/client/src/com/vaadin/client/ui/grid/GridHeader.java @@ -15,6 +15,8 @@ */ package com.vaadin.client.ui.grid; +import com.vaadin.client.ui.grid.Grid.AbstractGridColumn.SortableColumnHeaderRenderer; + /** * Represents the header section of a Grid. A header consists of a single header * row containing a header cell for each column. Each cell has a simple textual @@ -41,6 +43,16 @@ public class GridHeader extends GridStaticSection { */ public class HeaderRow extends GridStaticSection.StaticRow { + private boolean isDefault = false; + + protected void setDefault(boolean isDefault) { + this.isDefault = isDefault; + } + + public boolean isDefault() { + return isDefault; + } + @Override protected HeaderCell createCell() { return new HeaderCell(); @@ -54,6 +66,67 @@ public class GridHeader extends GridStaticSection { public class HeaderCell extends GridStaticSection.StaticCell { } + private HeaderRow defaultRow; + + @Override + public void removeRow(int index) { + HeaderRow removedRow = getRow(index); + super.removeRow(index); + if (removedRow == defaultRow) { + setDefaultRow(null); + } + } + + /** + * Sets the default row of this header. The default row is a special header + * row providing a user interface for sorting columns. + * + * @param row + * the new default row, or null for no default row + * + * @throws IllegalArgumentException + * this header does not contain the row + */ + public void setDefaultRow(HeaderRow row) { + if (row == defaultRow) { + return; + } + if (row != null && !getRows().contains(row)) { + throw new IllegalArgumentException( + "Cannot set a default row that does not exist in the container"); + } + if (defaultRow != null) { + assert defaultRow.getRenderer() instanceof SortableColumnHeaderRenderer; + + // Eclipse is wrong about this warning - javac does not accept the + // parameterized version + ((Grid.SortableColumnHeaderRenderer) defaultRow.getRenderer()) + .removeFromRow(defaultRow); + + defaultRow.setDefault(false); + } + if (row != null) { + assert !(row.getRenderer() instanceof SortableColumnHeaderRenderer); + + row.setRenderer(getGrid().new SortableColumnHeaderRenderer(row + .getRenderer())); + + row.setDefault(true); + } + defaultRow = row; + refreshGrid(); + } + + /** + * Returns the current default row of this header. The default row is a + * special header row providing a user interface for sorting columns. + * + * @return the default row or null if no default row set + */ + public HeaderRow getDefaultRow() { + return defaultRow; + } + @Override protected HeaderRow createRow() { return new HeaderRow(); diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index f455acc92e..4318811ca2 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -111,6 +111,10 @@ abstract class GridStaticSection> cells.remove(index); } + protected void setRenderer(Renderer renderer) { + this.renderer = renderer; + } + protected Renderer getRenderer() { return renderer; } @@ -227,11 +231,12 @@ abstract class GridStaticSection> * if the row does not exist in this section */ public void removeRow(ROWTYPE row) { - if (!rows.remove(row)) { + try { + removeRow(rows.indexOf(row)); + } catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException( "Section does not contain the given row"); } - refreshGrid(); } /** diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index e4e6dcf4be..67a97c74b7 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -225,8 +225,13 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { */ public Grid(final Container.Indexed datasource) { - getState().header.rows.add(new RowState()); + RowState headerDefaultRow = new RowState(); + headerDefaultRow.defaultRow = true; + getState().header.rows.add(headerDefaultRow); + + // FIXME By default there shouldn't be any footer row getState().footer.rows.add(new RowState()); + setColumnFootersVisible(false); setContainerDataSource(datasource); diff --git a/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java b/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java index 358c06d089..859e01f089 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java @@ -33,6 +33,8 @@ public class GridStaticSectionState implements Serializable { public static class RowState implements Serializable { public List cells = new ArrayList(); + + public boolean defaultRow = false; } public List rows = new ArrayList(); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java index 2ced9e16d4..1b27350f25 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java @@ -16,12 +16,16 @@ 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.Arrays; import java.util.List; import org.junit.Test; import com.vaadin.testbench.TestBenchElement; +import com.vaadin.tests.components.grid.GridElement.GridCellElement; public class GridHeaderTest extends GridStaticSectionTest { @@ -126,7 +130,41 @@ public class GridHeaderTest extends GridStaticSectionTest { 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")); + } + 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/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index 21d65d56ac..e013306dc0 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -31,6 +31,7 @@ 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.renderers.DateRenderer; import com.vaadin.client.ui.grid.renderers.HtmlRenderer; import com.vaadin.client.ui.grid.renderers.NumberRenderer; @@ -57,6 +58,7 @@ public class GridBasicClientFeatures extends private final Grid> grid; private final List> data; private final ListDataSource> ds; + private final ListSorter> sorter; /** * Our basic data object @@ -124,6 +126,8 @@ public class GridBasicClientFeatures extends grid.setDataSource(ds); grid.setSelectionMode(SelectionMode.NONE); + sorter = new ListSorter>(grid); + // Create a bunch of grid columns // Data source layout: @@ -247,6 +251,13 @@ public class GridBasicClientFeatures extends !grid.getColumn(index).isVisible()); } }, "Component", "Columns", "Column " + i); + addMenuCommand("Sortable", new ScheduledCommand() { + @Override + public void execute() { + grid.getColumn(index).setSortable( + !grid.getColumn(index).isSortable()); + } + }, "Component", "Columns", "Column " + i); } } @@ -278,6 +289,25 @@ public class GridBasicClientFeatures extends } }, 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() { -- cgit v1.2.3 From 64caee7afa90ac8b16ba48e768204aa36248ecbe Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Mon, 28 Jul 2014 16:26:01 +0300 Subject: Allow merging header and footer cells again #13334 This changeset adds the possibility to merge header and footer cells by using HeaderRow.join(). Note: Currently this does not support hidden columns, support for it should be added in a later changeset. Change-Id: I42e089ef2ac6eea304e355423b274159a79baa89 --- client/src/com/vaadin/client/ui/grid/Grid.java | 11 +- .../com/vaadin/client/ui/grid/GridConnector.java | 2 +- .../src/com/vaadin/client/ui/grid/GridFooter.java | 2 +- .../src/com/vaadin/client/ui/grid/GridHeader.java | 6 +- .../vaadin/client/ui/grid/GridStaticSection.java | 135 +++++++++++++++++++-- .../grid/basicfeatures/GridFooterTest.java | 55 +++++++++ .../grid/basicfeatures/GridHeaderTest.java | 51 ++++++++ .../client/grid/GridBasicClientFeatures.java | 79 +++++++++++- 8 files changed, 323 insertions(+), 18 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index ff75417c12..1e310e3ec4 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -46,6 +46,7 @@ import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; +import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.TextRenderer; import com.vaadin.client.ui.grid.renderers.WidgetRenderer; @@ -1436,9 +1437,15 @@ public class Grid extends Composite implements final List columnIndices = getVisibleColumnIndices(); for (FlyweightCell cell : cellsToUpdate) { + int index = columnIndices.get(cell.getColumn()); - gridRow.getRenderer().render(cell, - gridRow.getCell(index).getText()); + StaticCell metadata = gridRow.getCell(index); + + // Assign colspan to cell before rendering + cell.setColSpan(metadata.getColspan()); + + // Render + gridRow.getRenderer().render(cell, metadata.getText()); activeCellHandler.updateActiveCellStyle(cell, container); } diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 3c7629a60d..458dc7e1d2 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -377,7 +377,7 @@ public class GridConnector extends AbstractComponentConnector { section.setVisible(state.visible); - section.refreshGrid(); + section.refreshSection(); } /** diff --git a/client/src/com/vaadin/client/ui/grid/GridFooter.java b/client/src/com/vaadin/client/ui/grid/GridFooter.java index 7f478f7d29..eba6ad81cb 100644 --- a/client/src/com/vaadin/client/ui/grid/GridFooter.java +++ b/client/src/com/vaadin/client/ui/grid/GridFooter.java @@ -56,7 +56,7 @@ public class GridFooter extends GridStaticSection { } @Override - protected void refreshGrid() { + protected void refreshSection() { getGrid().refreshFooter(); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridHeader.java b/client/src/com/vaadin/client/ui/grid/GridHeader.java index c5b0febeca..4e046873f4 100644 --- a/client/src/com/vaadin/client/ui/grid/GridHeader.java +++ b/client/src/com/vaadin/client/ui/grid/GridHeader.java @@ -24,7 +24,7 @@ import com.vaadin.client.ui.grid.Grid.AbstractGridColumn.SortableColumnHeaderRen * * TODO Arbitrary number of header rows (zero included, one by default) * - * TODO Merging header cells + * TODO Account for hidden columns when merging header cells * * TODO "Default" row with sorting * @@ -114,7 +114,7 @@ public class GridHeader extends GridStaticSection { row.setDefault(true); } defaultRow = row; - refreshGrid(); + refreshSection(); } /** @@ -133,7 +133,7 @@ public class GridHeader extends GridStaticSection { } @Override - protected void refreshGrid() { + protected void refreshSection() { getGrid().refreshHeader(); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index 4318811ca2..fa4f3e5ea0 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -16,6 +16,9 @@ package com.vaadin.client.ui.grid; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import com.vaadin.client.ui.grid.renderers.TextRenderer; @@ -41,17 +44,19 @@ abstract class GridStaticSection> private String text = ""; + private int colspan = 1; + private GridStaticSection section; /** * Sets the text displayed in this cell. - * + * * @param text * a plain text caption */ public void setText(String text) { this.text = text; - section.refreshGrid(); + section.refreshSection(); } /** @@ -72,6 +77,21 @@ abstract class GridStaticSection> this.section = section; } + /** + * @return the colspan + */ + public int getColspan() { + return colspan; + } + + /** + * @param colspan + * the colspan to set + */ + public void setColspan(int colspan) { + this.colspan = colspan; + } + } /** @@ -88,6 +108,8 @@ abstract class GridStaticSection> private GridStaticSection section; + private Collection> cellGroups = new HashSet>(); + /** * Returns the cell at the given position in this row. * @@ -101,6 +123,105 @@ abstract class GridStaticSection> return cells.get(index); } + /** + * Merges cells in a row + * + * @param cells + * The cells to be merged + * @return The first cell of the merged cells + */ + protected CELLTYPE join(List cells) { + assert cells.size() > 1 : "You cannot merge less than 2 cells together"; + + // Ensure no cell is already grouped + for (CELLTYPE cell : cells) { + if (getCellGroupForCell(cell) != null) { + throw new IllegalStateException("Cell " + cell.getText() + + " is already grouped."); + } + } + + // Ensure continuous range + int firstCellIndex = this.cells.indexOf(cells.get(0)); + for (int i = 0; i < cells.size(); i++) { + if (this.cells.get(firstCellIndex + i) != cells.get(i)) { + throw new IllegalStateException( + "Cell range must be a continous range"); + } + } + + // Create a new group + cellGroups.add(new ArrayList(cells)); + + calculateColspans(); + + getSection().refreshSection(); + + // Returns first cell of group + return cells.get(0); + } + + /** + * Merges columns cells in a row + * + * @param columns + * The columns which header should be merged + * @return The remaining visible cell after the merge + */ + public CELLTYPE join(GridColumn... columns) { + assert columns.length > 1 : "You cannot merge less than 2 columns together"; + + // Convert columns to cells + List cells = new ArrayList(); + for (GridColumn c : columns) { + int index = getSection().getGrid().getColumns().indexOf(c); + cells.add(this.cells.get(index)); + } + + return join(cells); + } + + /** + * Merges columns cells in a row + * + * @param cells + * The cells to merge. Must be from the same row. + * @return The remaining visible cell after the merge + */ + public CELLTYPE join(CELLTYPE... cells) { + return join(Arrays.asList(cells)); + } + + private List getCellGroupForCell(CELLTYPE cell) { + for (List group : cellGroups) { + if (group.contains(cell)) { + return group; + } + } + return null; + } + + private void calculateColspans() { + // Reset all cells + for (CELLTYPE cell : cells) { + cell.setColspan(1); + } + + // Set colspan for grouped cells + for (List group : cellGroups) { + for (int i = 0; i < group.size(); i++) { + CELLTYPE cell = group.get(i); + if (i == 0) { + // Assign full colspan to first cell + cell.setColspan(group.size()); + } else { + // Hide other cells + cell.setColspan(0); + } + } + } + } + protected void addCell(int index) { CELLTYPE cell = createCell(); cell.setSection(getSection()); @@ -146,7 +267,7 @@ abstract class GridStaticSection> /** * Informs the grid that this section should be re-rendered. */ - protected abstract void refreshGrid(); + protected abstract void refreshSection(); /** * Sets the visibility of the whole section. @@ -156,7 +277,7 @@ abstract class GridStaticSection> */ public void setVisible(boolean visible) { this.visible = visible; - refreshGrid(); + refreshSection(); } /** @@ -185,7 +306,7 @@ abstract class GridStaticSection> row.addCell(i); } rows.add(index, row); - refreshGrid(); + refreshSection(); return row; } @@ -218,12 +339,12 @@ abstract class GridStaticSection> */ public void removeRow(int index) { rows.remove(index); - refreshGrid(); + refreshSection(); } /** * Removes the given row from the section. - * + * * @param row * the row to be removed * diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java index f7dd85e3c3..e117ed5fbb 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java @@ -16,9 +16,13 @@ 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 org.junit.Test; +import com.vaadin.tests.components.grid.GridElement.GridCellElement; + public class GridFooterTest extends GridStaticSectionTest { @Test @@ -85,6 +89,57 @@ public class GridFooterTest extends GridStaticSectionTest { 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("11", spannedCell.getAttribute("colspan")); + + for (int columnIndex = 1; columnIndex < 11; columnIndex++) { + GridCellElement hiddenCell = getGridElement().getFooterCell(0, + columnIndex); + assertFalse(hiddenCell.isDisplayed()); + } + } + private void assertFooterCount(int count) { assertEquals("footer count", count, getGridElement().getFooterCount()); } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java index 1b27350f25..771c0da810 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java @@ -159,6 +159,57 @@ public class GridHeaderTest extends GridStaticSectionTest { 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("11", spannedCell.getAttribute("colspan")); + + for (int columnIndex = 1; columnIndex < 11; columnIndex++) { + GridCellElement hiddenCell = getGridElement().getHeaderCell(1, + columnIndex); + assertFalse(hiddenCell.isDisplayed()); + } + } + private void assertHeaderCount(int count) { assertEquals("header count", count, getGridElement().getHeaderCount()); } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index e013306dc0..b6dfdc8635 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -311,13 +311,13 @@ public class GridBasicClientFeatures extends addMenuCommand("Prepend row", new ScheduledCommand() { @Override public void execute() { - setHeaderTexts(header.prependRow()); + configureHeaderRow(header.prependRow()); } }, menuPath); addMenuCommand("Append row", new ScheduledCommand() { @Override public void execute() { - setHeaderTexts(header.appendRow()); + configureHeaderRow(header.appendRow()); } }, menuPath); addMenuCommand("Remove top row", new ScheduledCommand() { @@ -332,6 +332,42 @@ public class GridBasicClientFeatures extends 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(0), row.getCell(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); } private void createFooterMenu() { @@ -348,13 +384,13 @@ public class GridBasicClientFeatures extends addMenuCommand("Prepend row", new ScheduledCommand() { @Override public void execute() { - setFooterTexts(footer.prependRow()); + configureFooterRow(footer.prependRow()); } }, menuPath); addMenuCommand("Append row", new ScheduledCommand() { @Override public void execute() { - setFooterTexts(footer.appendRow()); + configureFooterRow(footer.appendRow()); } }, menuPath); addMenuCommand("Remove top row", new ScheduledCommand() { @@ -371,6 +407,41 @@ public class GridBasicClientFeatures extends }, menuPath); } + 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(0), row.getCell(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 a renderer for a {@link Renderers} */ -- cgit v1.2.3 From 18308551b69b113368360e59c722d1dd4a314895 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 28 Jul 2014 14:16:41 +0300 Subject: Add multi column sorting test for Grid Change-Id: I3ff10c66fd4133ec794cc23c259e3fb6dc6ebec0 --- .../grid/basicfeatures/GridBasicFeatures.java | 12 ++++++++-- .../grid/basicfeatures/GridSortingTest.java | 26 ++++++++++++++++++++++ .../client/grid/GridBasicClientFeatures.java | 19 ++++++++++++++-- 3 files changed, 53 insertions(+), 4 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 316d7116e3..cfe3646295 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -52,8 +52,8 @@ import com.vaadin.ui.components.grid.sort.SortOrder; */ public class GridBasicFeatures extends AbstractComponentTest { - private static final int MANUALLY_FORMATTED_COLUMNS = 4; - public static final int COLUMNS = 11; + private static final int MANUALLY_FORMATTED_COLUMNS = 5; + public static final int COLUMNS = 12; public static final int ROWS = 1000; private int columnGroupRows = 0; @@ -86,6 +86,8 @@ public class GridBasicFeatures extends AbstractComponentTest { new Date()); ds.addContainerProperty(getColumnProperty(col++), String.class, ""); + // Random numbers + ds.addContainerProperty(getColumnProperty(col++), Integer.class, 0); ds.addContainerProperty(getColumnProperty(col++), Integer.class, 0); } @@ -110,8 +112,12 @@ public class GridBasicFeatures extends AbstractComponentTest { item.getItemProperty(getColumnProperty(col++)).setValue( "" + row + ""); + // Random numbers item.getItemProperty(getColumnProperty(col++)).setValue( rand.nextInt()); + // Random between 0 - 5 to test multisorting + item.getItemProperty(getColumnProperty(col++)).setValue( + rand.nextInt(5)); } } @@ -132,6 +138,8 @@ public class GridBasicFeatures extends AbstractComponentTest { new HtmlRenderer()); grid.getColumn(getColumnProperty(col++)).setRenderer( new NumberRenderer()); + grid.getColumn(getColumnProperty(col++)).setRenderer( + new NumberRenderer()); } // Add footer values (header values are automatically created) diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java index f706c1791d..4a1d7b7be1 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java @@ -23,6 +23,8 @@ import java.io.IOException; import org.junit.Ignore; import org.junit.Test; +import org.openqa.selenium.Keys; +import org.openqa.selenium.interactions.Actions; import com.vaadin.tests.components.grid.GridElement; @@ -158,6 +160,30 @@ public class GridSortingTest extends GridBasicFeaturesTest { assertEquals("11. Sort order: [Column7 DESCENDING]", 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 sortBy(String column) { selectMenuPath("Component", "State", "Sort by column", column); } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index b6dfdc8635..7d4b29ba5d 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -51,8 +51,8 @@ public class GridBasicClientFeatures extends TEXT_RENDERER, HTML_RENDERER, NUMBER_RENDERER, DATE_RENDERER; } - private static final int MANUALLY_FORMATTED_COLUMNS = 4; - public static final int COLUMNS = 11; + private static final int MANUALLY_FORMATTED_COLUMNS = 5; + public static final int COLUMNS = 12; public static final int ROWS = 1000; private final Grid> grid; @@ -118,6 +118,9 @@ public class GridBasicClientFeatures extends d = datarow.get(col++); d.value = Integer.valueOf(rand.nextInt()); + + d = datarow.get(col++); + d.value = Integer.valueOf(rand.nextInt(5)); } } @@ -200,6 +203,18 @@ public class GridBasicClientFeatures extends }); } + // Random integer value between 0 and 5 + { + final int c = col++; + grid.addColumn(new GridColumn>( + createRenderer(Renderers.NUMBER_RENDERER)) { + @Override + public Integer getValue(List row) { + return (Integer) row.get(c).value; + } + }); + } + setHeaderTexts(grid.getHeader().getRow(0)); // -- cgit v1.2.3 From f0cab759eeb61f0f5e5a5f33a0e7ae1168bf8d96 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 30 Jul 2014 10:19:48 +0300 Subject: Use GridBasicFeatures variable COLUMNS instead of hardcoded value Change-Id: Ide8c50c98ac86653cbc5ab7614465b7d26c10c81 --- .../vaadin/tests/components/grid/basicfeatures/GridFooterTest.java | 5 +++-- .../vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java index e117ed5fbb..c4e86369f9 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java @@ -131,9 +131,10 @@ public class GridFooterTest extends GridStaticSectionTest { GridCellElement spannedCell = getGridElement().getFooterCell(0, 0); assertTrue(spannedCell.isDisplayed()); - assertEquals("11", spannedCell.getAttribute("colspan")); + assertEquals("" + GridBasicFeatures.COLUMNS, + spannedCell.getAttribute("colspan")); - for (int columnIndex = 1; columnIndex < 11; columnIndex++) { + for (int columnIndex = 1; columnIndex < GridBasicFeatures.COLUMNS; columnIndex++) { GridCellElement hiddenCell = getGridElement().getFooterCell(0, columnIndex); assertFalse(hiddenCell.isDisplayed()); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java index 771c0da810..43d5aa47df 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java @@ -201,9 +201,10 @@ public class GridHeaderTest extends GridStaticSectionTest { GridCellElement spannedCell = getGridElement().getHeaderCell(1, 0); assertTrue(spannedCell.isDisplayed()); - assertEquals("11", spannedCell.getAttribute("colspan")); + assertEquals("" + GridBasicFeatures.COLUMNS, + spannedCell.getAttribute("colspan")); - for (int columnIndex = 1; columnIndex < 11; columnIndex++) { + for (int columnIndex = 1; columnIndex < GridBasicFeatures.COLUMNS; columnIndex++) { GridCellElement hiddenCell = getGridElement().getHeaderCell(1, columnIndex); assertFalse(hiddenCell.isDisplayed()); -- cgit v1.2.3 From 91f14489833ccad2f3c5aeaabfd4d5c4a5a60728 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 28 Jul 2014 12:25:32 +0300 Subject: Fix SelectionModelSingle when updating from server (#13334) Change-Id: I4ae1411b3833387e83c8951f9b08528cf1ba97b9 --- .../ui/grid/selection/SelectionModelSingle.java | 36 +++++------- .../grid/basicfeatures/GridSelectionTest.java | 65 ++++++++++++++++------ 2 files changed, 62 insertions(+), 39 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java index 2647ae9c56..2942538d81 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java +++ b/client/src/com/vaadin/client/ui/grid/selection/SelectionModelSingle.java @@ -68,20 +68,13 @@ public class SelectionModelSingle extends AbstractRowHandleSelectionModel throw new IllegalArgumentException("Row cannot be null"); } - if (isSelected(row)) { - return false; - } - T removed = getSelectedRow(); - if (selectedRow != null) { - selectedRow.unpin(); - } - selectedRow = grid.getDataSource().getHandle(row); - selectedRow.pin(); + if (selectByHandle(grid.getDataSource().getHandle(row))) { + grid.fireEvent(new SelectionChangeEvent(grid, row, removed)); - grid.fireEvent(new SelectionChangeEvent(grid, row, removed)); - - return true; + return true; + } + return false; } @Override @@ -92,10 +85,8 @@ public class SelectionModelSingle extends AbstractRowHandleSelectionModel } if (isSelected(row)) { - T removed = selectedRow.getRow(); - selectedRow.unpin(); - selectedRow = null; - grid.fireEvent(new SelectionChangeEvent(grid, null, removed)); + deselectByHandle(selectedRow); + grid.fireEvent(new SelectionChangeEvent(grid, null, row)); return true; } @@ -109,10 +100,8 @@ public class SelectionModelSingle extends AbstractRowHandleSelectionModel @Override public void reset() { - T removed = getSelectedRow(); - - if (removed != null) { - deselect(removed); + if (selectedRow != null) { + deselect(getSelectedRow()); } } @@ -126,8 +115,10 @@ public class SelectionModelSingle extends AbstractRowHandleSelectionModel @Override protected boolean selectByHandle(RowHandle handle) { - if (!handle.equals(selectedRow)) { + if (handle != null && !handle.equals(selectedRow)) { + deselectByHandle(selectedRow); selectedRow = handle; + selectedRow.pin(); return true; } else { return false; @@ -136,7 +127,8 @@ public class SelectionModelSingle extends AbstractRowHandleSelectionModel @Override protected boolean deselectByHandle(RowHandle handle) { - if (handle.equals(selectedRow)) { + if (handle != null && handle.equals(selectedRow)) { + selectedRow.unpin(); selectedRow = null; return true; } else { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.java index e18dc1faa4..873c222f80 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.java @@ -21,7 +21,8 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import com.vaadin.testbench.TestBenchElement; -import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; +import com.vaadin.tests.components.grid.GridElement; +import com.vaadin.tests.components.grid.GridElement.GridRowElement; public class GridSelectionTest extends GridBasicFeaturesTest { @@ -31,12 +32,12 @@ public class GridSelectionTest extends GridBasicFeaturesTest { setSelectionModelMulti(); - assertFalse("row shouldn't start out as selected", - isSelected(getRow(0))); + assertFalse("row shouldn't start out as selected", getRow(0) + .isSelected()); toggleFirstRowSelection(); - assertTrue("row should become selected", isSelected(getRow(0))); + assertTrue("row should become selected", getRow(0).isSelected()); toggleFirstRowSelection(); - assertFalse("row shouldn't remain selected", isSelected(getRow(0))); + assertFalse("row shouldn't remain selected", getRow(0).isSelected()); } @Test @@ -45,16 +46,16 @@ public class GridSelectionTest extends GridBasicFeaturesTest { setSelectionModelMulti(); - assertFalse("row shouldn't start out as selected", - isSelected(getRow(0))); + assertFalse("row shouldn't start out as selected", getRow(0) + .isSelected()); toggleFirstRowSelection(); - assertTrue("row should become selected", isSelected(getRow(0))); + 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", isSelected(getRow(0))); + + "back into view", getRow(0).isSelected()); } @Test @@ -63,18 +64,18 @@ public class GridSelectionTest extends GridBasicFeaturesTest { setSelectionModelMulti(); - assertFalse("row shouldn't start out as selected", - isSelected(getRow(0))); + 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", isSelected(getRow(0))); + + "back into view", getRow(0).isSelected()); toggleFirstRowSelection(); - assertFalse("row shouldn't remain selected", isSelected(getRow(0))); + assertFalse("row shouldn't remain selected", getRow(0).isSelected()); } @Test @@ -83,8 +84,8 @@ public class GridSelectionTest extends GridBasicFeaturesTest { setSelectionModelMulti(); - assertFalse("row shouldn't start out as selected", - isSelected(getRow(0))); + assertFalse("row shouldn't start out as selected", getRow(0) + .isSelected()); scrollGridVerticallyTo(10000); // make sure the row is out of cache toggleFirstRowSelection(); @@ -92,13 +93,43 @@ public class GridSelectionTest extends GridBasicFeaturesTest { scrollGridVerticallyTo(0); // make sure the row is out of cache assertFalse("row shouldn't be selected when scrolling " - + "back into view", isSelected(getRow(0))); + + "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()); } 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) { /* @@ -113,7 +144,7 @@ public class GridSelectionTest extends GridBasicFeaturesTest { selectMenuPath("Component", "Body rows", "Select first row"); } - private TestBenchElement getRow(int i) { + private GridRowElement getRow(int i) { return getGridElement().getRow(i); } } -- cgit v1.2.3 From 5d0aa11b2c83e7f5abfa4c6d9ef71871b810a016 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 29 Jul 2014 17:19:28 +0300 Subject: Add server side API for Headers and Footers (#13334) Change-Id: I52f282089cc55b1f281b9aeb934886442b0c34f3 --- server/src/com/vaadin/ui/components/grid/Grid.java | 66 +++-- .../com/vaadin/ui/components/grid/GridColumn.java | 17 +- .../com/vaadin/ui/components/grid/GridFooter.java | 66 +++++ .../com/vaadin/ui/components/grid/GridHeader.java | 124 ++++++++++ .../ui/components/grid/GridStaticSection.java | 273 +++++++++++++++++++++ .../tests/server/component/grid/GridColumns.java | 32 ++- .../grid/basicfeatures/GridBasicFeatures.java | 135 ++++++++-- .../basicfeatures/GridKeyboardNavigationTest.java | 4 +- .../grid/basicfeatures/GridSortingTest.java | 33 ++- .../grid/basicfeatures/GridStructureTest.java | 37 ++- 10 files changed, 679 insertions(+), 108 deletions(-) create mode 100644 server/src/com/vaadin/ui/components/grid/GridFooter.java create mode 100644 server/src/com/vaadin/ui/components/grid/GridHeader.java create mode 100644 server/src/com/vaadin/ui/components/grid/GridStaticSection.java (limited to 'uitest/src') diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 67a97c74b7..f5846c0148 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -46,12 +46,11 @@ import com.vaadin.shared.ui.grid.GridColumnState; import com.vaadin.shared.ui.grid.GridServerRpc; import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.GridState.SharedSelectionMode; -import com.vaadin.shared.ui.grid.GridStaticSectionState.CellState; -import com.vaadin.shared.ui.grid.GridStaticSectionState.RowState; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.shared.ui.grid.SortDirection; import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.components.grid.GridHeader.HeaderRow; import com.vaadin.ui.components.grid.selection.MultiSelectionModel; import com.vaadin.ui.components.grid.selection.NoSelectionModel; import com.vaadin.ui.components.grid.selection.SelectionChangeEvent; @@ -209,6 +208,9 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { */ private int ignoreSelectionClientSync = 0; + private final GridHeader header = new GridHeader(this); + private final GridFooter footer = new GridFooter(this); + private static final Method SELECTION_CHANGE_METHOD = ReflectTools .findMethod(SelectionChangeListener.class, "selectionChange", SelectionChangeEvent.class); @@ -224,17 +226,8 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * the data source for the grid */ public Grid(final Container.Indexed datasource) { - - RowState headerDefaultRow = new RowState(); - headerDefaultRow.defaultRow = true; - getState().header.rows.add(headerDefaultRow); - - // FIXME By default there shouldn't be any footer row - getState().footer.rows.add(new RowState()); - - setColumnFootersVisible(false); - setContainerDataSource(datasource); + setSelectionMode(SelectionMode.MULTI); addSelectionChangeListener(new SelectionChangeListener() { @Override @@ -433,6 +426,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { setLastFrozenPropertyId(null); // Add columns + HeaderRow row = getHeader().getDefaultRow(); for (Object propertyId : datasource.getContainerPropertyIds()) { if (!columns.containsKey(propertyId)) { GridColumn column = appendColumn(propertyId); @@ -445,7 +439,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { } // Add by default property id as column header - column.setHeaderCaption(String.valueOf(propertyId)); + row.getCell(propertyId).setText(String.valueOf(propertyId)); } } } @@ -476,8 +470,9 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * @param visible * true if the header rows should be visible */ + @Deprecated public void setColumnHeadersVisible(boolean visible) { - getState().header.visible = visible; + getHeader().setVisible(visible); } /** @@ -485,8 +480,9 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * * @return true if the headers of the columns are visible */ + @Deprecated public boolean isColumnHeadersVisible() { - return getState(false).header.visible; + return getHeader().isVisible(); } /** @@ -495,8 +491,9 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * @param visible * true if the footer rows should be visible */ + @Deprecated public void setColumnFootersVisible(boolean visible) { - getState().footer.visible = visible; + getFooter().setVisible(visible); } /** @@ -504,8 +501,9 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * * @return true if the footer rows should be visible */ + @Deprecated public boolean isColumnFootersVisible() { - return getState(false).footer.visible; + return getFooter().isVisible(); } /** @@ -537,6 +535,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * * @return a column group instance you can use to add column groups */ + @Deprecated public ColumnGroupRow addColumnGroupRow() { ColumnGroupRowState state = new ColumnGroupRowState(); ColumnGroupRow row = new ColumnGroupRow(this, state, columnKeys); @@ -552,6 +551,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * the index of the row * @return a column group instance you can use to add column groups */ + @Deprecated public ColumnGroupRow addColumnGroupRow(int rowIndex) { ColumnGroupRowState state = new ColumnGroupRowState(); ColumnGroupRow row = new ColumnGroupRow(this, state, columnKeys); @@ -566,6 +566,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * @param row * the row to remove */ + @Deprecated public void removeColumnGroupRow(ColumnGroupRow row) { columnGroupRows.remove(row); getState().columnGroupRows.remove(row.getState()); @@ -576,6 +577,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { * * @return an unmodifiable list of column group rows */ + @Deprecated public List getColumnGroupRows() { return Collections.unmodifiableList(new ArrayList( columnGroupRows)); @@ -635,11 +637,13 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { GridColumnState columnState = new GridColumnState(); columnState.id = columnKeys.key(datasourcePropertyId); getState().columns.add(columnState); - for (RowState row : getState().header.rows) { - row.cells.add(new CellState()); + + for (int i = 0; i < getHeader().getRowCount(); ++i) { + getHeader().getRow(i).addCell(datasourcePropertyId); } - for (RowState row : getState().footer.rows) { - row.cells.add(new CellState()); + + for (int i = 0; i < getFooter().getRowCount(); ++i) { + getFooter().getRow(i).addCell(datasourcePropertyId); } GridColumn column = new GridColumn(this, columnState); @@ -1316,4 +1320,24 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { removeListener(SortOrderChangeEvent.class, listener, SORT_ORDER_CHANGE_METHOD); } + + /** + * Returns the header section of this grid. The default header contains a + * single row displaying the column captions. + * + * @return the header + */ + public GridHeader getHeader() { + return header; + } + + /** + * Returns the footer section of this grid. The default header contains a + * single row displaying the column captions. + * + * @return the footer + */ + public GridFooter getFooter() { + return footer; + } } diff --git a/server/src/com/vaadin/ui/components/grid/GridColumn.java b/server/src/com/vaadin/ui/components/grid/GridColumn.java index 667b4f86db..0ef805eb2e 100644 --- a/server/src/com/vaadin/ui/components/grid/GridColumn.java +++ b/server/src/com/vaadin/ui/components/grid/GridColumn.java @@ -82,14 +82,15 @@ public class GridColumn implements Serializable { * Returns the caption of the header. By default the header caption is the * property id of the column. * - * @return the text in the header + * @return the text in the default row of header, null if no default row * * @throws IllegalStateException * if the column no longer is attached to the grid */ + @Deprecated public String getHeaderCaption() throws IllegalStateException { checkColumnIsAttached(); - return getHeaderCellState().text; + return state.header; } /** @@ -101,11 +102,10 @@ public class GridColumn implements Serializable { * @throws IllegalStateException * if the column is no longer attached to any grid */ + @Deprecated public void setHeaderCaption(String caption) throws IllegalStateException { checkColumnIsAttached(); - getHeaderCellState().text = caption; state.header = caption; - grid.markAsDirty(); } /** @@ -116,6 +116,7 @@ public class GridColumn implements Serializable { * @throws IllegalStateException * if the column is no longer attached to any grid */ + @Deprecated public String getFooterCaption() throws IllegalStateException { checkColumnIsAttached(); return getFooterCellState().text; @@ -130,6 +131,7 @@ public class GridColumn implements Serializable { * @throws IllegalStateException * if the column is no longer attached to any grid */ + @Deprecated public void setFooterCaption(String caption) throws IllegalStateException { checkColumnIsAttached(); getFooterCellState().text = caption; @@ -137,11 +139,6 @@ public class GridColumn implements Serializable { grid.markAsDirty(); } - private CellState getHeaderCellState() { - int index = grid.getState().columns.indexOf(state); - return grid.getState().header.rows.get(0).cells.get(index); - } - private CellState getFooterCellState() { int index = grid.getState().columns.indexOf(state); return grid.getState().footer.rows.get(0).cells.get(index); @@ -252,7 +249,7 @@ public class GridColumn implements Serializable { * the renderer to use * @throws IllegalArgumentException * if no compatible converter could be found - * + * * @see VaadinSession#getConverterFactory() * @see ConverterUtil#getConverter(Class, Class, VaadinSession) * @see #setConverter(Converter) diff --git a/server/src/com/vaadin/ui/components/grid/GridFooter.java b/server/src/com/vaadin/ui/components/grid/GridFooter.java new file mode 100644 index 0000000000..e4a7eab5d1 --- /dev/null +++ b/server/src/com/vaadin/ui/components/grid/GridFooter.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.grid; + +import com.vaadin.shared.ui.grid.GridStaticSectionState; + +/** + * Represents the footer section of a Grid. By default Footer is not visible. + * + * @since + * @author Vaadin Ltd + */ +public class GridFooter extends GridStaticSection { + + public class FooterRow extends GridStaticSection.StaticRow { + + protected FooterRow(GridStaticSection section) { + super(section); + } + + @Override + protected FooterCell createCell() { + return new FooterCell(this); + } + + } + + public class FooterCell extends GridStaticSection.StaticCell { + + protected FooterCell(FooterRow row) { + super(row); + } + } + + private final GridStaticSectionState footerState = new GridStaticSectionState(); + + protected GridFooter(Grid grid) { + this.grid = grid; + grid.getState(true).footer = footerState; + setVisible(false); + } + + @Override + protected GridStaticSectionState getState() { + return footerState; + } + + @Override + protected FooterRow createRow() { + return new FooterRow(this); + } + +} diff --git a/server/src/com/vaadin/ui/components/grid/GridHeader.java b/server/src/com/vaadin/ui/components/grid/GridHeader.java new file mode 100644 index 0000000000..f8bd3c6642 --- /dev/null +++ b/server/src/com/vaadin/ui/components/grid/GridHeader.java @@ -0,0 +1,124 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.grid; + +import com.vaadin.shared.ui.grid.GridStaticSectionState; + +/** + * Represents the header section of a Grid. + * + * @since + * @author Vaadin Ltd + */ +public class GridHeader extends GridStaticSection { + + public class HeaderRow extends GridStaticSection.StaticRow { + + protected HeaderRow(GridStaticSection section) { + super(section); + } + + private void setDefaultRow(boolean value) { + getRowState().defaultRow = value; + } + + @Override + protected HeaderCell createCell() { + return new HeaderCell(this); + } + } + + public class HeaderCell extends GridStaticSection.StaticCell { + + protected HeaderCell(HeaderRow row) { + super(row); + } + } + + private HeaderRow defaultRow = null; + private final GridStaticSectionState headerState = new GridStaticSectionState(); + + protected GridHeader(Grid grid) { + this.grid = grid; + grid.getState(true).header = headerState; + HeaderRow row = createRow(); + rows.add(row); + setDefaultRow(row); + getState().rows.add(row.getRowState()); + } + + /** + * Sets the default row of this header. The default row is a special header + * row providing a user interface for sorting columns. + * + * @param row + * the new default row, or null for no default row + * + * @throws IllegalArgumentException + * this header does not contain the row + */ + public void setDefaultRow(HeaderRow row) { + if (row == defaultRow) { + return; + } + + if (row != null && !rows.contains(row)) { + throw new IllegalArgumentException( + "Cannot set a default row that does not exist in the section"); + } + + if (defaultRow != null) { + defaultRow.setDefaultRow(false); + } + + if (row != null) { + row.setDefaultRow(true); + } + + defaultRow = row; + markAsDirty(); + } + + /** + * Returns the current default row of this header. The default row is a + * special header row providing a user interface for sorting columns. + * + * @return the default row or null if no default row set + */ + public HeaderRow getDefaultRow() { + return defaultRow; + } + + @Override + protected GridStaticSectionState getState() { + return headerState; + } + + @Override + protected HeaderRow createRow() { + return new HeaderRow(this); + } + + @Override + public HeaderRow removeRow(int rowIndex) { + HeaderRow row = super.removeRow(rowIndex); + if (row == defaultRow) { + // Default Header Row was just removed. + setDefaultRow(null); + } + return row; + } +} diff --git a/server/src/com/vaadin/ui/components/grid/GridStaticSection.java b/server/src/com/vaadin/ui/components/grid/GridStaticSection.java new file mode 100644 index 0000000000..80d822e7bc --- /dev/null +++ b/server/src/com/vaadin/ui/components/grid/GridStaticSection.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.ui.components.grid; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.vaadin.data.Container.Indexed; +import com.vaadin.shared.ui.grid.GridStaticSectionState; +import com.vaadin.shared.ui.grid.GridStaticSectionState.CellState; +import com.vaadin.shared.ui.grid.GridStaticSectionState.RowState; + +/** + * Abstract base class for Grid header and footer sections. + * + * @since + * @author Vaadin Ltd + * @param + * the type of the rows in the section + */ +abstract class GridStaticSection> + implements Serializable { + + /** + * Abstract base class for Grid header and footer rows. + * + * @param + * the type of the cells in the row + */ + abstract static class StaticRow> implements + Serializable { + + private RowState rowState = new RowState(); + protected GridStaticSection section; + private Map cells = new LinkedHashMap(); + + protected StaticRow(GridStaticSection section) { + this.section = section; + } + + protected void addCell(Object propertyId) { + CELLTYPE cell = createCell(); + cells.put(propertyId, cell); + rowState.cells.add(cell.getCellState()); + } + + /** + * Creates and returns a new instance of the cell type. + * + * @return the created cell + */ + protected abstract CELLTYPE createCell(); + + protected RowState getRowState() { + return rowState; + } + + /** + * Returns the cell at the given position in this row. + * + * @param propertyId + * the itemId of column + * @return the cell on given column + * @throws IndexOutOfBoundsException + * if the index is out of bounds + */ + public CELLTYPE getCell(Object propertyId) { + return cells.get(propertyId); + } + } + + /** + * A header or footer cell. Has a simple textual caption. + * + * @param + * the type of row this cells is in + */ + abstract static class StaticCell> implements + Serializable { + + private CellState cellState = new CellState(); + private ROWTYPE row; + + protected StaticCell(ROWTYPE row) { + this.row = row; + } + + /** + * Gets the row where this cell is. + * + * @return row for this cell + */ + public ROWTYPE getRow() { + return row; + } + + protected CellState getCellState() { + return cellState; + } + + /** + * Gets the current text content of this cell. Text is null if HTML or + * Component content is used. + * + * @return text content or null + */ + public String getText() { + return cellState.text; + } + + /** + * Sets the current text content of this cell. + * + * @param text + * new text content + */ + public void setText(String text) { + if (text != null && !text.equals(getCellState().text)) { + getCellState().text = text; + row.section.markAsDirty(); + } + } + } + + protected Grid grid; + protected List rows = new ArrayList(); + + /** + * Sets the visibility of the whole section. + * + * @param visible + * true to show this section, false to hide + */ + public void setVisible(boolean visible) { + if (getState().visible != visible) { + getState().visible = visible; + markAsDirty(); + } + } + + /** + * Returns the visibility of this section. + * + * @return true if visible, false otherwise. + */ + public boolean isVisible() { + return getState().visible; + } + + /** + * Removes the row at the given position. + * + * @param index + * the position of the row + * + * @throws IndexOutOfBoundsException + * if the index is out of bounds + */ + public ROWTYPE removeRow(int rowIndex) { + ROWTYPE row = rows.remove(rowIndex); + getState().rows.remove(rowIndex); + + markAsDirty(); + return row; + } + + /** + * Removes the given row from the section. + * + * @param row + * the row to be removed + * + * @throws IllegalArgumentException + * if the row does not exist in this section + */ + public void removeRow(ROWTYPE row) { + try { + removeRow(rows.indexOf(row)); + } catch (IndexOutOfBoundsException e) { + throw new IllegalArgumentException( + "Section does not contain the given row"); + } + } + + /** + * Gets row at given index. + * + * @param rowIndex + * 0 based index for row. Counted from top to bottom + * @return row at given index + */ + public ROWTYPE getRow(int rowIndex) { + return rows.get(rowIndex); + } + + /** + * Adds a new row at the top of this section. + * + * @return the new row + */ + public ROWTYPE prependRow() { + return addRowAt(0); + } + + /** + * Adds a new row at the bottom of this section. + * + * @return the new row + */ + public ROWTYPE appendRow() { + return addRowAt(rows.size()); + } + + /** + * Inserts a new row at the given position. + * + * @param index + * the position at which to insert the row + * @return the new row + * + * @throws IndexOutOfBoundsException + * if the index is out of bounds + */ + public ROWTYPE addRowAt(int index) { + ROWTYPE row = createRow(); + rows.add(index, row); + getState().rows.add(index, row.getRowState()); + + Indexed dataSource = grid.getContainerDatasource(); + for (Object id : dataSource.getContainerPropertyIds()) { + row.addCell(id); + } + + markAsDirty(); + return row; + } + + /** + * Gets the amount of rows in this section. + * + * @return row count + */ + public int getRowCount() { + return rows.size(); + } + + protected abstract GridStaticSectionState getState(); + + protected abstract ROWTYPE createRow(); + + /** + * Informs the grid that state has changed and it should be redrawn. + */ + protected void markAsDirty() { + grid.markAsDirty(); + } +} diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java index 9d71d21d59..d1c821cc54 100644 --- a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java +++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java @@ -77,7 +77,8 @@ public class GridColumns { assertNotNull(column); // Property id should be the column header by default - assertEquals(propertyId.toString(), column.getHeaderCaption()); + assertEquals(propertyId.toString(), grid.getHeader() + .getDefaultRow().getCell(propertyId).getText()); } } @@ -88,11 +89,6 @@ public class GridColumns { GridColumn column = grid.getColumn("column1"); assertNotNull(column); - column.setFooterCaption("CustomFooter"); - assertEquals("CustomFooter", column.getFooterCaption()); - assertEquals(column.getFooterCaption(), - getColumnState("column1").footer); - column.setHeaderCaption("CustomHeader"); assertEquals("CustomHeader", column.getHeaderCaption()); assertEquals(column.getHeaderCaption(), @@ -174,31 +170,31 @@ public class GridColumns { @Test public void testHeaderVisiblility() throws Exception { - assertTrue(grid.isColumnHeadersVisible()); + assertTrue(grid.getHeader().isVisible()); assertTrue(state.header.visible); - grid.setColumnHeadersVisible(false); - assertFalse(grid.isColumnHeadersVisible()); + grid.getHeader().setVisible(false); + assertFalse(grid.getHeader().isVisible()); assertFalse(state.header.visible); - grid.setColumnHeadersVisible(true); - assertTrue(grid.isColumnHeadersVisible()); + grid.getHeader().setVisible(true); + assertTrue(grid.getHeader().isVisible()); assertTrue(state.header.visible); } @Test public void testFooterVisibility() throws Exception { - assertFalse(grid.isColumnFootersVisible()); - assertFalse(state.footer.visible); - - grid.setColumnFootersVisible(false); - assertFalse(grid.isColumnFootersVisible()); + assertFalse(grid.getFooter().isVisible()); assertFalse(state.footer.visible); - grid.setColumnFootersVisible(true); - assertTrue(grid.isColumnFootersVisible()); + grid.getFooter().setVisible(true); + assertTrue(grid.getFooter().isVisible()); assertTrue(state.footer.visible); + + grid.getFooter().setVisible(false); + assertFalse(grid.getFooter().isVisible()); + assertFalse(state.footer.visible); } @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index cfe3646295..bff16d8db7 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -36,6 +36,9 @@ import com.vaadin.ui.components.grid.ColumnGroupRow; 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.GridHeader; +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; @@ -142,15 +145,20 @@ public class GridBasicFeatures extends AbstractComponentTest { 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++) { - grid.getColumn(getColumnProperty(col)).setFooterCaption( - "Footer " + col); + footer.getRow(0).getCell(getColumnProperty(col)) + .setText("Footer " + col); } // Set varying column widths for (int col = 0; col < COLUMNS; col++) { - grid.getColumn("Column" + col).setWidth(100 + col * 50); + grid.getColumn(getColumnProperty(col)).setWidth(100 + col * 50); } grid.addSortOrderChangeListener(new SortOrderChangeListener() { @@ -226,29 +234,125 @@ public class GridBasicFeatures extends AbstractComponentTest { } protected void createHeaderActions() { - createCategory("Headers", null); + createCategory("Header", null); - createBooleanAction("Visible", "Headers", true, + createBooleanAction("Visible", "Header", true, new Command() { @Override public void execute(Grid grid, Boolean value, Object data) { - grid.setColumnHeadersVisible(value); + grid.getHeader().setVisible(value); } }); + + LinkedHashMap defaultRows = new LinkedHashMap(); + defaultRows.put("Top", "Top"); + defaultRows.put("Bottom", "Bottom"); + defaultRows.put("Unset", "Unset"); + + createMultiClickAction("Default row", "Header", defaultRows, + new Command() { + + @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() { + + @Override + public void execute(Grid grid, Object value, Object data) { + grid.getHeader().prependRow(); + } + + }, null); + createClickAction("Append row", "Header", new Command() { + + @Override + public void execute(Grid grid, Object value, Object data) { + grid.getHeader().appendRow(); + } + + }, null); + + createClickAction("Remove top row", "Header", + new Command() { + + @Override + public void execute(Grid grid, Object value, Object data) { + grid.getHeader().removeRow(0); + } + + }, null); + createClickAction("Remove bottom row", "Header", + new Command() { + + @Override + public void execute(Grid grid, Object value, Object data) { + grid.getHeader().removeRow( + grid.getHeader().getRowCount() - 1); + } + + }, null); } protected void createFooterActions() { - createCategory("Footers", null); + createCategory("Footer", null); - createBooleanAction("Visible", "Footers", false, + createBooleanAction("Visible", "Footer", false, new Command() { @Override public void execute(Grid grid, Boolean value, Object data) { - grid.setColumnFootersVisible(value); + grid.getFooter().setVisible(value); } }); + + createClickAction("Prepend row", "Footer", new Command() { + + @Override + public void execute(Grid grid, Object value, Object data) { + grid.getFooter().prependRow(); + } + + }, null); + createClickAction("Append row", "Footer", new Command() { + + @Override + public void execute(Grid grid, Object value, Object data) { + grid.getFooter().appendRow(); + } + + }, null); + + createClickAction("Remove top row", "Footer", + new Command() { + + @Override + public void execute(Grid grid, Object value, Object data) { + grid.getFooter().removeRow(0); + } + + }, null); + createClickAction("Remove bottom row", "Footer", + new Command() { + + @Override + public void execute(Grid grid, Object value, Object data) { + grid.getFooter().removeRow( + grid.getFooter().getRowCount() - 1); + } + + }, null); } protected void createColumnActions() { @@ -278,7 +382,8 @@ public class GridBasicFeatures extends AbstractComponentTest { @Override public void execute(Grid grid, String value, Object data) { grid.getContainerDatasource() - .removeContainerProperty("Column" + data); + .removeContainerProperty( + getColumnProperty((Integer) data)); } }, null, c); @@ -287,7 +392,7 @@ public class GridBasicFeatures extends AbstractComponentTest { @Override public void execute(Grid grid, String value, Object data) { - grid.setLastFrozenPropertyId("Column" + data); + grid.setLastFrozenPropertyId(getColumnProperty((Integer) data)); } }, null, c); @@ -306,9 +411,9 @@ public class GridBasicFeatures extends AbstractComponentTest { } }, c); - createCategory("Column" + c + " Width", getColumnProperty(c)); + createCategory("Column " + c + " Width", getColumnProperty(c)); - createClickAction("Auto", "Column" + c + " Width", + createClickAction("Auto", "Column " + c + " Width", new Command() { @Override @@ -324,7 +429,7 @@ public class GridBasicFeatures extends AbstractComponentTest { }, -1, c); for (int w = 50; w < 300; w += 50) { - createClickAction(w + "px", "Column" + c + " Width", + createClickAction(w + "px", "Column " + c + " Width", new Command() { @Override @@ -343,7 +448,7 @@ public class GridBasicFeatures extends AbstractComponentTest { } private static String getColumnProperty(int c) { - return "Column" + c; + return "Column " + c; } protected void createColumnGroupActions() { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java index 805213027e..e20b45bd1d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java @@ -104,7 +104,7 @@ public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { public void testNavigationFromFooterToBody() { openTestURL(); - selectMenuPath("Component", "Footers", "Visible"); + selectMenuPath("Component", "Footer", "Visible"); GridElement grid = getGridElement(); grid.scrollToRow(300); @@ -146,7 +146,7 @@ public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { public void testNavigateBetweenFooterAndBodyWithTab() { openTestURL(); - selectMenuPath("Component", "Footers", "Visible"); + selectMenuPath("Component", "Footer", "Visible"); GridElement grid = getGridElement(); grid.getCell(10, 2).click(); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java index 4a1d7b7be1..ee3f2a632b 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java @@ -21,7 +21,6 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; -import org.junit.Ignore; import org.junit.Test; import org.openqa.selenium.Keys; import org.openqa.selenium.interactions.Actions; @@ -30,11 +29,7 @@ import com.vaadin.tests.components.grid.GridElement; public class GridSortingTest extends GridBasicFeaturesTest { - /* - * TODO unignore once column header captions are reimplemented - */ @Test - @Ignore public void testProgrammaticSorting() throws IOException { openTestURL(); @@ -43,7 +38,7 @@ public class GridSortingTest extends GridBasicFeaturesTest { // 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("Column9, DESC"); + sortBy("Column 9, DESC"); assertTrue("Column 9 should have the sort-desc stylename", grid .getHeaderCell(0, 9).getAttribute("class") @@ -53,12 +48,12 @@ public class GridSortingTest extends GridBasicFeaturesTest { for (int i = 0; i < 3; ++i) { row += "9"; assertEquals( - "Grid is not sorted by Column9 using descending direction.", + "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("Column10, ASC"); + sortBy("Column 10, ASC"); assertFalse( "Column 9 should no longer have the sort-desc stylename", @@ -75,7 +70,7 @@ public class GridSortingTest extends GridBasicFeaturesTest { for (int i = 0; i < 5; ++i) { assertGreater( - "Grid is not sorted by Column10 using ascending direction", + "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())); @@ -83,10 +78,10 @@ public class GridSortingTest extends GridBasicFeaturesTest { // Column 7 is row index as a number. Last three row are original rows // 2, 1 and 0. - sortBy("Column7, DESC"); + sortBy("Column 7, DESC"); for (int i = 0; i < 3; ++i) { assertEquals( - "Grid is not sorted by Column7 using descending direction", + "Grid is not sorted by Column 7 using descending direction", "(" + i + ", 0)", grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText()); } @@ -118,18 +113,18 @@ public class GridSortingTest extends GridBasicFeaturesTest { for (int i = 0; i < 3; ++i) { row += "9"; assertEquals( - "Grid is not sorted by Column9 using descending direction.", + "Grid is not sorted by Column 9 using descending direction.", "(" + row + ", 0)", grid.getCell(i, 0).getText()); } - assertEquals("2. Sort order: [Column9 ASCENDING]", getLogRow(2)); - assertEquals("4. Sort order: [Column9 DESCENDING]", getLogRow(0)); + assertEquals("2. Sort order: [Column 9 ASCENDING]", getLogRow(2)); + assertEquals("4. Sort order: [Column 9 DESCENDING]", 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: [Column10 ASCENDING]", getLogRow(0)); + assertEquals("6. Sort order: [Column 10 ASCENDING]", getLogRow(0)); // Not cleaning up correctly causes exceptions when scrolling. grid.scrollToRow(50); @@ -138,7 +133,7 @@ public class GridSortingTest extends GridBasicFeaturesTest { for (int i = 0; i < 5; ++i) { assertGreater( - "Grid is not sorted by Column10 using ascending direction", + "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())); @@ -151,13 +146,13 @@ public class GridSortingTest extends GridBasicFeaturesTest { grid.getHeaderCell(0, 7).click(); for (int i = 0; i < 3; ++i) { assertEquals( - "Grid is not sorted by Column7 using descending direction", + "Grid is not sorted by Column 7 using descending direction", "(" + i + ", 0)", grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText()); } - assertEquals("9. Sort order: [Column7 ASCENDING]", getLogRow(3)); - assertEquals("11. Sort order: [Column7 DESCENDING]", getLogRow(1)); + assertEquals("9. Sort order: [Column 7 ASCENDING]", getLogRow(3)); + assertEquals("11. Sort order: [Column 7 DESCENDING]", getLogRow(1)); } @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java index 94f04e10a2..ced6963c32 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.assertTrue; import java.util.List; -import org.junit.Ignore; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; @@ -31,44 +30,36 @@ import com.vaadin.testbench.TestBenchElement; public class GridStructureTest extends GridBasicFeaturesTest { - /* - * TODO unignore once column header captions are reimplemented - */ @Test - @Ignore public void testHidingColumn() throws Exception { openTestURL(); // Column 0 should be visible List cells = getGridHeaderRowCells(); - assertEquals("Column0", cells.get(0).getText()); + assertEquals("Column 0", cells.get(0).getText()); // Hide column 0 - selectMenuPath("Component", "Columns", "Column0", "Visible"); + selectMenuPath("Component", "Columns", "Column 0", "Visible"); // Column 1 should now be the first cell cells = getGridHeaderRowCells(); - assertEquals("Column1", cells.get(0).getText()); + assertEquals("Column 1", cells.get(0).getText()); } - /* - * TODO unignore once column header captions are reimplemented - */ @Test - @Ignore public void testRemovingColumn() throws Exception { openTestURL(); // Column 0 should be visible List cells = getGridHeaderRowCells(); - assertEquals("Column0", cells.get(0).getText()); + assertEquals("Column 0", cells.get(0).getText()); // Hide column 0 - selectMenuPath("Component", "Columns", "Column0", "Remove"); + selectMenuPath("Component", "Columns", "Column 0", "Remove"); // Column 1 should now be the first cell cells = getGridHeaderRowCells(); - assertEquals("Column1", cells.get(0).getText()); + assertEquals("Column 1", cells.get(0).getText()); } @Test @@ -76,9 +67,9 @@ public class GridStructureTest extends GridBasicFeaturesTest { openTestURL(); // Remove columns 2,3,4 - selectMenuPath("Component", "Columns", "Column2", "Remove"); - selectMenuPath("Component", "Columns", "Column3", "Remove"); - selectMenuPath("Component", "Columns", "Column4", "Remove"); + 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); @@ -95,7 +86,7 @@ public class GridStructureTest extends GridBasicFeaturesTest { openTestURL(); // Freeze column 2 - selectMenuPath("Component", "Columns", "Column2", "Freeze"); + selectMenuPath("Component", "Columns", "Column 2", "Freeze"); WebElement cell = getBodyCellByRowAndColumn(0, 0); assertTrue(cell.getAttribute("class").contains("frozen")); @@ -127,20 +118,20 @@ public class GridStructureTest extends GridBasicFeaturesTest { assertEquals(100, cell.getSize().getWidth()); // Set first column to be 200px wide - selectMenuPath("Component", "Columns", "Column0", "Column0 Width", + selectMenuPath("Component", "Columns", "Column 0", "Column 0 Width", "200px"); cell = getBodyCellByRowAndColumn(0, 0); assertEquals(200, cell.getSize().getWidth()); // Set second column to be 150px wide - selectMenuPath("Component", "Columns", "Column1", "Column1 Width", + selectMenuPath("Component", "Columns", "Column 1", "Column 1 Width", "150px"); cell = getBodyCellByRowAndColumn(0, 1); assertEquals(150, cell.getSize().getWidth()); // Set first column to be auto sized (defaults to 100px currently) - selectMenuPath("Component", "Columns", "Column0", "Column0 Width", + selectMenuPath("Component", "Columns", "Column 0", "Column 0 Width", "Auto"); cell = getBodyCellByRowAndColumn(0, 0); @@ -203,7 +194,7 @@ public class GridStructureTest extends GridBasicFeaturesTest { selectMenuPath("Component", "Body rows", "Modify first row (getContainerProperty)"); assertEquals("(Second) modification with getItemProperty failed", - "modified: Column0", getBodyCellByRowAndColumn(0, 0).getText()); + "modified: Column 0", getBodyCellByRowAndColumn(0, 0).getText()); } private void assertPrimaryStylename(String stylename) { -- cgit v1.2.3 From b51f6ebc0d0e60d20f40f4492e865d990b80ceb2 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Thu, 31 Jul 2014 15:34:58 +0300 Subject: Fixes setting width before adding column to grid #13334 Change-Id: Iddc16a9b84b2d52b39d44280b3d73a656c971fd0 --- client/src/com/vaadin/client/ui/grid/Grid.java | 9 +--- .../GridClientColumnPropertiesTest.java | 58 ++++++++++++++++++++++ .../client/grid/GridBasicClientFeatures.java | 26 +++++++++- 3 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientColumnPropertiesTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index d946be3d9e..dbfaf15813 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -1193,14 +1193,7 @@ public class Grid extends Composite implements * @return pixel width of the column */ public int getWidth() { - if (grid == null) { - return width; - } else { - int index = findIndexOfColumn(); - ColumnConfiguration conf = grid.escalator - .getColumnConfiguration(); - return conf.getColumnWidth(index); - } + return width; } /** diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientColumnPropertiesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientColumnPropertiesTest.java new file mode 100644 index 0000000000..c9e048cc7f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientColumnPropertiesTest.java @@ -0,0 +1,58 @@ +/* + * 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 com.vaadin.tests.widgetset.client.grid.GridBasicClientFeatures; + +public class GridClientColumnPropertiesTest extends GridBasicClientFeaturesTest { + + @Test + public void initialColumnWidths() { + openTestURL(); + + for (int col = 0; col < GridBasicClientFeatures.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); + } + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index 7d4b29ba5d..1c9758b669 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -145,13 +145,17 @@ public class GridBasicClientFeatures extends final int c = col; - grid.addColumn(new GridColumn>( + GridColumn> column = new GridColumn>( createRenderer(Renderers.TEXT_RENDERER)) { @Override public String getValue(List row) { return (String) row.get(c).value; } - }); + }; + + column.setWidth(50 + c * 25); + + grid.addColumn(column); } @@ -273,6 +277,24 @@ public class GridBasicClientFeatures extends !grid.getColumn(index).isSortable()); } }, "Component", "Columns", "Column " + i); + addMenuCommand("auto", new ScheduledCommand() { + @Override + public void execute() { + grid.getColumn(index).setWidth(-1); + } + }, "Component", "Columns", "Column " + i, "Width"); + addMenuCommand("50px", new ScheduledCommand() { + @Override + public void execute() { + grid.getColumn(index).setWidth(50); + } + }, "Component", "Columns", "Column " + i, "Width"); + addMenuCommand("200px", new ScheduledCommand() { + @Override + public void execute() { + grid.getColumn(index).setWidth(200); + } + }, "Component", "Columns", "Column " + i, "Width"); } } -- cgit v1.2.3 From 27d1b5cb864cb56f41d796d552e4a1d6c2637fa8 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Wed, 30 Jul 2014 15:03:11 +0300 Subject: Removed deprecated header and footer renderers #13334 Removed header and footer renderers as well as some other deprecated setters which has been replaced with direct access to the header cells. Change-Id: Ibaec4b098ebddd4b6ba74c96827e55f9808828d8 --- client/src/com/vaadin/client/ui/grid/Grid.java | 202 --------------------- .../com/vaadin/client/ui/grid/GridConnector.java | 2 - .../com/vaadin/client/ui/grid/sort/SortOrder.java | 6 - .../grid/GridClientColumnRendererConnector.java | 27 +-- 4 files changed, 16 insertions(+), 221 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index dbfaf15813..f800a8cb3b 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -48,7 +48,6 @@ import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; -import com.vaadin.client.ui.grid.renderers.TextRenderer; import com.vaadin.client.ui.grid.renderers.WidgetRenderer; import com.vaadin.client.ui.grid.selection.HasSelectionChangeHandlers; import com.vaadin.client.ui.grid.selection.SelectionChangeEvent; @@ -66,7 +65,6 @@ import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.Range; import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.shared.ui.grid.SortDirection; -import com.vaadin.shared.util.SharedUtil; /** * A data grid view that supports columns and lazy loading of data rows from a @@ -429,62 +427,12 @@ public class Grid extends Composite implements public SelectionColumn(final Renderer selectColumnRenderer) { super(selectColumnRenderer); - - setHeaderRenderer(new Renderer() { - @Override - public void render(FlyweightCell cell, String data) { - if (cell.getRow() == escalator.getHeader().getRowCount() - 1) { - // TODO: header "select all / select none" logic - selectColumnRenderer.render(cell, Boolean.FALSE); - } - } - }); } public void initDone() { initDone = true; } - @Override - public void setFooterCaption(String caption) { - if (!SharedUtil.equals(caption, getFooterCaption()) && initDone) { - throw new UnsupportedOperationException("The selection " - + "column cannot be modified after init"); - } else { - super.setFooterCaption(caption); - } - } - - @Override - public void setFooterRenderer(Renderer renderer) { - if (!SharedUtil.equals(renderer, getFooterRenderer()) && initDone) { - throw new UnsupportedOperationException("The selection " - + "column cannot be modified after init"); - } else { - super.setFooterRenderer(renderer); - } - } - - @Override - public void setHeaderCaption(String caption) { - if (!SharedUtil.equals(caption, getHeaderCaption()) && initDone) { - throw new UnsupportedOperationException("The selection " - + "column cannot be modified after init"); - } else { - super.setHeaderCaption(caption); - } - } - - @Override - public void setHeaderRenderer(Renderer renderer) { - if (!SharedUtil.equals(renderer, getHeaderRenderer()) && initDone) { - throw new UnsupportedOperationException("The selection " - + "column cannot be modified after init"); - } else { - super.setHeaderRenderer(renderer); - } - } - @Override public void setVisible(boolean visible) { if (!visible && initDone) { @@ -917,18 +865,6 @@ public class Grid extends Composite implements */ private Renderer bodyRenderer; - /** - * Renderer for rendering the header cell value into the cell - */ - @Deprecated - private Renderer headerRenderer = new TextRenderer(); - - /** - * Renderer for rendering the footer cell value into the cell - */ - @Deprecated - private Renderer footerRenderer = new TextRenderer(); - private boolean sortable = false; /** @@ -944,28 +880,6 @@ public class Grid extends Composite implements bodyRenderer = renderer; } - /** - * Constructs a new column with custom renderers for rows, header and - * footer cells. - * - * @param bodyRenderer - * The renderer to use for rendering body cells - * @param headerRenderer - * The renderer to use for rendering header cells - * @param footerRenderer - * The renderer to use for rendering footer cells - */ - public AbstractGridColumn(Renderer bodyRenderer, - Renderer headerRenderer, Renderer footerRenderer) { - this(bodyRenderer); - if (headerRenderer == null || footerRenderer == null) { - throw new IllegalArgumentException("Renderer cannot be null."); - } - - this.headerRenderer = headerRenderer; - this.footerRenderer = footerRenderer; - } - /** * Internally used by the grid to set itself * @@ -981,120 +895,6 @@ public class Grid extends Composite implements this.grid = grid; } - /** - * Gets text in the header of the column. By default the header caption - * is empty. - * - * @return the text displayed in the column caption - */ - @Deprecated - public String getHeaderCaption() { - return header; - } - - /** - * Returns the renderer used for rendering the header cells - * - * @return a renderer that renders header cells - */ - @Deprecated - public Renderer getHeaderRenderer() { - return headerRenderer; - } - - /** - * Sets the renderer that renders header cells. Should not be null. - * - * @param renderer - * The renderer to use for rendering header cells. - */ - @Deprecated - public void setHeaderRenderer(Renderer renderer) { - if (renderer == null) { - throw new IllegalArgumentException("Renderer cannot be null."); - } - this.headerRenderer = headerRenderer; - if (grid != null) { - grid.refreshHeader(); - } - } - - /** - * Returns the renderer used for rendering the footer cells - * - * @return a renderer that renders footer cells - */ - @Deprecated - public Renderer getFooterRenderer() { - return footerRenderer; - } - - /** - * Sets the renderer that renders footer cells. Should not be null. - * - * @param renderer - * The renderer to use for rendering footer cells. - */ - @Deprecated - public void setFooterRenderer(Renderer renderer) { - if (renderer == null) { - throw new IllegalArgumentException("Renderer cannot be null."); - } - footerRenderer = renderer; - if (grid != null) { - grid.refreshFooter(); - } - } - - /** - * Sets the text in the header of the column. - * - * @param caption - * the text displayed in the column header - */ - @Deprecated - public void setHeaderCaption(String caption) { - if (SharedUtil.equals(caption, header)) { - return; - } - - header = caption; - - if (grid != null) { - grid.refreshHeader(); - } - } - - /** - * Gets text in the footer of the column. By default the footer caption - * is empty. - * - * @return The text displayed in the footer of the column - */ - @Deprecated - public String getFooterCaption() { - return footer; - } - - /** - * Sets text in the footer of the column. - * - * @param caption - * the text displayed in the footer of the column - */ - @Deprecated - public void setFooterCaption(String caption) { - if (SharedUtil.equals(caption, footer)) { - return; - } - - footer = caption; - - if (grid != null) { - grid.refreshFooter(); - } - } - /** * Is the column visible. By default all columns are visible. * @@ -1607,9 +1407,7 @@ public class Grid extends Composite implements // Sink all renderer events Set events = new HashSet(); - events.addAll(getConsumedEventsForRenderer(column.getHeaderRenderer())); events.addAll(getConsumedEventsForRenderer(column.getRenderer())); - events.addAll(getConsumedEventsForRenderer(column.getFooterRenderer())); sinkEvents(events); } diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 7582bee0bf..2a06aba3e6 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -393,8 +393,6 @@ public class GridConnector extends AbstractComponentConnector { private static void updateColumnFromState(GridColumn column, GridColumnState state) { column.setVisible(state.visible); - column.setHeaderCaption(state.header); - column.setFooterCaption(state.footer); column.setWidth(state.width); column.setSortable(state.sortable); } diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java index 34279bdc04..682beda793 100644 --- a/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java +++ b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java @@ -69,10 +69,4 @@ public class SortOrder { public SortDirection getDirection() { return direction; } - - @Override - public String toString() { - return column.getHeaderCaption() + " (" + direction + ")"; - } - } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index 549d6eee85..e685034c7b 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -136,8 +136,8 @@ public class GridClientColumnRendererConnector extends // Add a column to display the data in GridColumn c = createColumnWithRenderer(Renderers.TEXT_RENDERER); - c.setHeaderCaption("Column 1"); grid.addColumn(c); + grid.getHeader().getDefaultRow().getCell(0).setText("Column 1"); // Add method for testing sort event firing grid.addSortHandler(new SortEventHandler() { @@ -148,7 +148,11 @@ public class GridClientColumnRendererConnector extends String text = "Client-side sort event received
" + "Columns: " + event.getOrder().size() + ", order: "; for (SortOrder order : event.getOrder()) { - text += order.getColumn().getHeaderCaption() + ": " + int colIdx = getWidget().getColumns().indexOf( + order.getColumn()); + String columnHeader = getWidget().getHeader() + .getDefaultRow().getCell(colIdx).getText(); + text += columnHeader + ": " + order.getDirection().toString(); } console.setInnerHTML(text); @@ -164,25 +168,26 @@ public class GridClientColumnRendererConnector extends if (renderer == Renderers.NUMBER_RENDERER) { GridColumn numberColumn = createNumberColumnWithRenderer(renderer); - numberColumn.setHeaderCaption("Column " - + String.valueOf(getWidget() - .getColumnCount() + 1)); getWidget().addColumn(numberColumn); } else if (renderer == Renderers.DATE_RENDERER) { GridColumn dateColumn = createDateColumnWithRenderer(renderer); - dateColumn.setHeaderCaption("Column " - + String.valueOf(getWidget() - .getColumnCount() + 1)); getWidget().addColumn(dateColumn); } else { GridColumn column = createColumnWithRenderer(renderer); - column.setHeaderCaption("Column " - + String.valueOf(getWidget() - .getColumnCount() + 1)); getWidget().addColumn(column); } + + int idx = getWidget().getColumnCount() - 1; + getWidget() + .getHeader() + .getDefaultRow() + .getCell(idx) + .setText( + "Column " + + String.valueOf(getWidget() + .getColumnCount() + 1)); } @Override -- cgit v1.2.3 From e16a0fb28ec04266ab01b6b9ff001b19cf32944b Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Mon, 4 Aug 2014 12:51:37 +0300 Subject: Remove deprecated header/footer API (#13334) Change-Id: I9bddef300a817fd31054515e97bc6924370d3475 --- .../com/vaadin/ui/components/grid/ColumnGroup.java | 165 ----------- .../vaadin/ui/components/grid/ColumnGroupRow.java | 303 --------------------- server/src/com/vaadin/ui/components/grid/Grid.java | 125 --------- .../server/component/grid/GridColumnGroups.java | 260 ------------------ .../vaadin/shared/ui/grid/ColumnGroupRowState.java | 46 ---- .../src/com/vaadin/shared/ui/grid/GridState.java | 5 - .../tests/components/grid/GridColumnGroups.java | 106 ------- .../grid/basicfeatures/GridBasicFeatures.java | 70 ----- 8 files changed, 1080 deletions(-) delete mode 100644 server/src/com/vaadin/ui/components/grid/ColumnGroup.java delete mode 100644 server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java delete mode 100644 server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java delete mode 100644 shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java (limited to 'uitest/src') diff --git a/server/src/com/vaadin/ui/components/grid/ColumnGroup.java b/server/src/com/vaadin/ui/components/grid/ColumnGroup.java deleted file mode 100644 index ec676dfb87..0000000000 --- a/server/src/com/vaadin/ui/components/grid/ColumnGroup.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.vaadin.ui.components.grid; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.vaadin.shared.ui.grid.ColumnGroupState; - -/** - * Column groups are used to group columns together for adding common auxiliary - * headers and footers. Columns groups are added to {@link ColumnGroupRow}'s. - * - * @since - * @author Vaadin Ltd - */ -public class ColumnGroup implements Serializable { - - /** - * List of property ids belonging to this group - */ - private List columns; - - /** - * The grid the column group is associated with - */ - private final Grid grid; - - /** - * The column group row the column group is attached to - */ - private final ColumnGroupRow row; - - /** - * The common state between the server and the client - */ - private final ColumnGroupState state; - - /** - * Constructs a new column group - * - * @param grid - * the grid the column group is associated with - * @param state - * the state representing the data of the grid. Sent to the - * client - * @param propertyIds - * the property ids of the columns that belongs to the group - * @param groups - * the sub groups who should be included in this group - * - */ - ColumnGroup(Grid grid, ColumnGroupRow row, ColumnGroupState state, - List propertyIds) { - if (propertyIds == null) { - throw new IllegalArgumentException( - "propertyIds cannot be null. Use empty list instead."); - } - - this.state = state; - this.row = row; - columns = Collections.unmodifiableList(new ArrayList( - propertyIds)); - this.grid = grid; - } - - /** - * Sets the text displayed in the header of the column group. - * - * @param header - * the text displayed in the header of the column - */ - public void setHeaderCaption(String header) { - checkGroupIsAttached(); - state.header = header; - grid.markAsDirty(); - } - - /** - * Sets the text displayed in the header of the column group. - * - * @return the text displayed in the header of the column - */ - public String getHeaderCaption() { - checkGroupIsAttached(); - return state.header; - } - - /** - * Sets the text displayed in the footer of the column group. - * - * @param footer - * the text displayed in the footer of the column - */ - public void setFooterCaption(String footer) { - checkGroupIsAttached(); - state.footer = footer; - grid.markAsDirty(); - } - - /** - * The text displayed in the footer of the column group. - * - * @return the text displayed in the footer of the column - */ - public String getFooterCaption() { - checkGroupIsAttached(); - return state.footer; - } - - /** - * Is a property id in this group or in some sub group of this group. - * - * @param propertyId - * the property id to check for - * @return true if the property id is included in this group. - */ - public boolean isColumnInGroup(Object propertyId) { - if (columns.contains(propertyId)) { - return true; - } - return false; - } - - /** - * Returns a list of property ids where all also the child groups property - * ids are included. - * - * @return a unmodifiable list with all the columns in the group. Includes - * any subgroup columns as well. - */ - public List getColumns() { - return columns; - } - - /** - * Checks if column group is attached to a row and throws an - * {@link IllegalStateException} if it is not. - * - * @throws IllegalStateException - * if the column is no longer attached to any grid - */ - protected void checkGroupIsAttached() throws IllegalStateException { - if (!row.getState().groups.contains(state)) { - throw new IllegalStateException( - "Column Group has been removed from the row."); - } - } -} diff --git a/server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java b/server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java deleted file mode 100644 index a497b5a8a8..0000000000 --- a/server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.vaadin.ui.components.grid; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import com.vaadin.server.KeyMapper; -import com.vaadin.shared.ui.grid.ColumnGroupRowState; -import com.vaadin.shared.ui.grid.ColumnGroupState; - -/** - * A column group row represents an auxiliary header or footer row added to the - * grid. A column group row includes column groups that group columns together. - * - * @since - * @author Vaadin Ltd - */ -public class ColumnGroupRow implements Serializable { - - /** - * The common state shared between the client and server - */ - private final ColumnGroupRowState state; - - /** - * The column groups in this row - */ - private List groups = new ArrayList(); - - /** - * Grid that the group row belongs to - */ - private final Grid grid; - - /** - * The column keys used to identify the column on the client side - */ - private final KeyMapper columnKeys; - - /** - * Constructs a new column group - * - * @param grid - * The grid that the column group is associated to - * @param state - * The shared state which contains the data shared between server - * and client - * @param columnKeys - * The column key mapper for converting property ids to client - * side column identifiers - */ - ColumnGroupRow(Grid grid, ColumnGroupRowState state, - KeyMapper columnKeys) { - this.grid = grid; - this.columnKeys = columnKeys; - this.state = state; - } - - /** - * Gets the shared state for the column group row. Used internally to send - * the group row to the client. - * - * @return The current state of the row - */ - ColumnGroupRowState getState() { - return state; - } - - /** - * Add a new group to the row by using property ids for the columns. - * - * @param propertyIds - * The property ids of the columns that should be included in the - * group. A column can only belong in group on a row at a time. - * @return a column group representing the collection of columns added to - * the group - */ - public ColumnGroup addGroup(Object... propertyIds) - throws IllegalArgumentException { - assert propertyIds != null : "propertyIds cannot be null."; - - for (Object propertyId : propertyIds) { - if (hasColumnBeenGrouped(propertyId)) { - throw new IllegalArgumentException("Column " - + String.valueOf(propertyId) - + " already belongs to another group."); - } - } - - validateNewGroupProperties(Arrays.asList(propertyIds)); - - ColumnGroupState state = new ColumnGroupState(); - for (Object propertyId : propertyIds) { - assert propertyId != null : "null items in columns array not supported."; - state.columns.add(columnKeys.key(propertyId)); - } - this.state.groups.add(state); - - ColumnGroup group = new ColumnGroup(grid, this, state, - Arrays.asList(propertyIds)); - groups.add(group); - - grid.markAsDirty(); - return group; - } - - private void validateNewGroupProperties(List propertyIds) - throws IllegalArgumentException { - - /* - * Validate parent grouping - */ - int rowIndex = grid.getColumnGroupRows().indexOf(this); - int parentRowIndex = rowIndex - 1; - - // Get the parent row of this row. - ColumnGroupRow parentRow = null; - if (parentRowIndex > -1) { - parentRow = grid.getColumnGroupRows().get(parentRowIndex); - } - - if (parentRow == null) { - // A parentless row is always valid and is usually the first row - // added to the grid - return; - } - - for (Object id : propertyIds) { - if (parentRow.hasColumnBeenGrouped(id)) { - /* - * If a property has been grouped in the parent row then all of - * the properties in the parent group also needs to be included - * in the child group for the groups to be valid - */ - ColumnGroup parentGroup = parentRow.getGroupForProperty(id); - if (!propertyIds.containsAll(parentGroup.getColumns())) { - throw new IllegalArgumentException( - "Grouped properties overlaps previous grouping bounderies"); - } - } - } - } - - /** - * Add a new group to the row by using column instances. - * - * @param columns - * the columns that should belong to the group - * @return a column group representing the collection of columns added to - * the group - */ - public ColumnGroup addGroup(GridColumn... columns) - throws IllegalArgumentException { - assert columns != null : "columns cannot be null"; - - List propertyIds = new ArrayList(); - for (GridColumn column : columns) { - assert column != null : "null items in columns array not supported."; - - String columnId = column.getState().id; - Object propertyId = grid.getPropertyIdByColumnId(columnId); - propertyIds.add(propertyId); - } - return addGroup(propertyIds.toArray()); - } - - /** - * Add a new group to the row by using other already greated groups - * - * @param groups - * the subgroups of the group - * @return a column group representing the collection of columns added to - * the group - * - */ - public ColumnGroup addGroup(ColumnGroup... groups) - throws IllegalArgumentException { - assert groups != null : "groups cannot be null"; - - // Gather all groups columns into one list - List propertyIds = new ArrayList(); - for (ColumnGroup group : groups) { - propertyIds.addAll(group.getColumns()); - } - - validateNewGroupProperties(propertyIds); - - ColumnGroupState state = new ColumnGroupState(); - ColumnGroup group = new ColumnGroup(grid, this, state, propertyIds); - this.groups.add(group); - - // Update state - for (Object propertyId : group.getColumns()) { - state.columns.add(columnKeys.key(propertyId)); - } - this.state.groups.add(state); - - grid.markAsDirty(); - return group; - } - - /** - * Removes a group from the row. Does not remove the group from subgroups, - * to remove it from the subgroup invoke removeGroup on the subgroup. - * - * @param group - * the group to remove - */ - public void removeGroup(ColumnGroup group) { - int index = groups.indexOf(group); - groups.remove(index); - state.groups.remove(index); - grid.markAsDirty(); - } - - /** - * Get the groups in the row. - * - * @return unmodifiable list of groups in this row - */ - public List getGroups() { - return Collections.unmodifiableList(groups); - } - - /** - * Checks if a property id has been added to a group in this row. - * - * @param propertyId - * the property id to check for - * @return true if the column is included in a group - */ - private boolean hasColumnBeenGrouped(Object propertyId) { - return getGroupForProperty(propertyId) != null; - } - - private ColumnGroup getGroupForProperty(Object propertyId) { - for (ColumnGroup group : groups) { - if (group.isColumnInGroup(propertyId)) { - return group; - } - } - return null; - } - - /** - * Is the header visible for the row. - * - * @return true if header is visible - */ - public boolean isHeaderVisible() { - return state.headerVisible; - } - - /** - * Sets the header visible for the row. - * - * @param visible - * should the header be shown - */ - public void setHeaderVisible(boolean visible) { - state.headerVisible = visible; - grid.markAsDirty(); - } - - /** - * Is the footer visible for the row. - * - * @return true if footer is visible - */ - public boolean isFooterVisible() { - return state.footerVisible; - } - - /** - * Sets the footer visible for the row. - * - * @param visible - * should the footer be shown - */ - public void setFooterVisible(boolean visible) { - state.footerVisible = visible; - grid.markAsDirty(); - } - -} diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 514a0496e2..5e21c7b70a 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -40,7 +40,6 @@ import com.vaadin.data.Container.Sortable; import com.vaadin.data.RpcDataProviderExtension; import com.vaadin.data.RpcDataProviderExtension.DataProviderKeyMapper; import com.vaadin.server.KeyMapper; -import com.vaadin.shared.ui.grid.ColumnGroupRowState; import com.vaadin.shared.ui.grid.GridClientRpc; import com.vaadin.shared.ui.grid.GridColumnState; import com.vaadin.shared.ui.grid.GridServerRpc; @@ -138,11 +137,6 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { */ private final KeyMapper columnKeys = new KeyMapper(); - /** - * The column groups added to the grid - */ - private final List columnGroupRows = new ArrayList(); - /** * The current sort order */ @@ -464,125 +458,6 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { return columns.get(propertyId); } - /** - * Sets the header rows visible. - * - * @param visible - * true if the header rows should be visible - */ - @Deprecated - public void setColumnHeadersVisible(boolean visible) { - getHeader().setVisible(visible); - } - - /** - * Are the header rows visible? - * - * @return true if the headers of the columns are visible - */ - @Deprecated - public boolean isColumnHeadersVisible() { - return getHeader().isVisible(); - } - - /** - * Sets the footer rows visible. - * - * @param visible - * true if the footer rows should be visible - */ - @Deprecated - public void setColumnFootersVisible(boolean visible) { - getFooter().setVisible(visible); - } - - /** - * Are the footer rows visible. - * - * @return true if the footer rows should be visible - */ - @Deprecated - public boolean isColumnFootersVisible() { - return getFooter().isVisible(); - } - - /** - *

- * Adds a new column group to the grid. - * - *

- * Column group rows are rendered in the header and footer of the grid. - * Column group rows are made up of column groups which groups together - * columns for adding a common auxiliary header or footer for the columns. - *

- *

- * - *

- * Example usage: - * - *

-     * // Add a new column group row to the grid
-     * ColumnGroupRow row = grid.addColumnGroupRow();
-     * 
-     * // Group "Column1" and "Column2" together to form a header in the row
-     * ColumnGroup column12 = row.addGroup("Column1", "Column2");
-     * 
-     * // Set a common header for "Column1" and "Column2"
-     * column12.setHeader("Column 1&2");
-     * 
- * - *

- * - * @return a column group instance you can use to add column groups - */ - @Deprecated - public ColumnGroupRow addColumnGroupRow() { - ColumnGroupRowState state = new ColumnGroupRowState(); - ColumnGroupRow row = new ColumnGroupRow(this, state, columnKeys); - columnGroupRows.add(row); - getState().columnGroupRows.add(state); - return row; - } - - /** - * Adds a new column group to the grid at a specific index - * - * @param rowIndex - * the index of the row - * @return a column group instance you can use to add column groups - */ - @Deprecated - public ColumnGroupRow addColumnGroupRow(int rowIndex) { - ColumnGroupRowState state = new ColumnGroupRowState(); - ColumnGroupRow row = new ColumnGroupRow(this, state, columnKeys); - columnGroupRows.add(rowIndex, row); - getState().columnGroupRows.add(rowIndex, state); - return row; - } - - /** - * Removes a column group. - * - * @param row - * the row to remove - */ - @Deprecated - public void removeColumnGroupRow(ColumnGroupRow row) { - columnGroupRows.remove(row); - getState().columnGroupRows.remove(row.getState()); - } - - /** - * Gets the column group rows. - * - * @return an unmodifiable list of column group rows - */ - @Deprecated - public List getColumnGroupRows() { - return Collections.unmodifiableList(new ArrayList( - columnGroupRows)); - } - /** * Used internally by the {@link Grid} to get a {@link GridColumn} by * referencing its generated state id. Also used by {@link GridColumn} to diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java deleted file mode 100644 index 21bfbbb37e..0000000000 --- a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumnGroups.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.server.component.grid; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; - -import com.vaadin.data.util.IndexedContainer; -import com.vaadin.server.KeyMapper; -import com.vaadin.shared.ui.grid.GridState; -import com.vaadin.ui.components.grid.ColumnGroup; -import com.vaadin.ui.components.grid.ColumnGroupRow; -import com.vaadin.ui.components.grid.Grid; - -public class GridColumnGroups { - - private Grid grid; - - private GridState state; - - private Method getStateMethod; - - private Field columnIdGeneratorField; - - private KeyMapper columnIdMapper; - - @Before - public void setup() throws Exception { - IndexedContainer ds = new IndexedContainer(); - for (int c = 0; c < 10; c++) { - ds.addContainerProperty("column" + c, String.class, ""); - } - grid = new Grid(ds); - - getStateMethod = Grid.class.getDeclaredMethod("getState"); - getStateMethod.setAccessible(true); - - state = (GridState) getStateMethod.invoke(grid); - - columnIdGeneratorField = Grid.class.getDeclaredField("columnKeys"); - columnIdGeneratorField.setAccessible(true); - - columnIdMapper = (KeyMapper) columnIdGeneratorField.get(grid); - } - - @Test - public void testColumnGroupRows() throws Exception { - - // No column group rows by default - List rows = grid.getColumnGroupRows(); - assertEquals(0, rows.size()); - - // Add some rows - ColumnGroupRow row1 = grid.addColumnGroupRow(); - ColumnGroupRow row3 = grid.addColumnGroupRow(); - ColumnGroupRow row2 = grid.addColumnGroupRow(1); - - rows = grid.getColumnGroupRows(); - assertEquals(3, rows.size()); - assertEquals(row1, rows.get(0)); - assertEquals(row2, rows.get(1)); - assertEquals(row3, rows.get(2)); - - // Header should be visible by default, footer should not - assertTrue(row1.isHeaderVisible()); - assertFalse(row1.isFooterVisible()); - - row1.setHeaderVisible(false); - assertFalse(row1.isHeaderVisible()); - row1.setHeaderVisible(true); - assertTrue(row1.isHeaderVisible()); - - row1.setFooterVisible(true); - assertTrue(row1.isFooterVisible()); - row1.setFooterVisible(false); - assertFalse(row1.isFooterVisible()); - - row1.setHeaderVisible(true); - row1.setFooterVisible(true); - assertTrue(row1.isHeaderVisible()); - assertTrue(row1.isFooterVisible()); - - row1.setHeaderVisible(false); - row1.setFooterVisible(false); - assertFalse(row1.isHeaderVisible()); - assertFalse(row1.isFooterVisible()); - } - - @Test - public void testColumnGroupsInState() throws Exception { - - // Add a new row - ColumnGroupRow row = grid.addColumnGroupRow(); - assertTrue(state.columnGroupRows.size() == 1); - - // Add a group by property id - ColumnGroup columns12 = row.addGroup("column1", "column2"); - assertTrue(state.columnGroupRows.get(0).groups.size() == 1); - - // Set header of column - columns12.setHeaderCaption("Column12"); - assertEquals("Column12", - state.columnGroupRows.get(0).groups.get(0).header); - - // Set footer of column - columns12.setFooterCaption("Footer12"); - assertEquals("Footer12", - state.columnGroupRows.get(0).groups.get(0).footer); - - // Add another group by column instance - ColumnGroup columns34 = row.addGroup(grid.getColumn("column3"), - grid.getColumn("column4")); - assertTrue(state.columnGroupRows.get(0).groups.size() == 2); - - // add another group row - ColumnGroupRow row2 = grid.addColumnGroupRow(); - assertTrue(state.columnGroupRows.size() == 2); - - // add a group by combining the two previous groups - ColumnGroup columns1234 = row2.addGroup(columns12, columns34); - assertTrue(columns1234.getColumns().size() == 4); - - // Insert a group as the second group - ColumnGroupRow newRow2 = grid.addColumnGroupRow(1); - assertTrue(state.columnGroupRows.size() == 3); - } - - @Test - public void testAddingColumnGroups() throws Exception { - - ColumnGroupRow row = grid.addColumnGroupRow(); - - // By property id - ColumnGroup columns01 = row.addGroup("column0", "column1"); - assertEquals(2, columns01.getColumns().size()); - assertEquals("column0", columns01.getColumns().get(0)); - assertTrue(columns01.isColumnInGroup("column0")); - assertEquals("column1", columns01.getColumns().get(1)); - assertTrue(columns01.isColumnInGroup("column1")); - - // By grid column - ColumnGroup columns23 = row.addGroup(grid.getColumn("column2"), - grid.getColumn("column3")); - assertEquals(2, columns23.getColumns().size()); - assertEquals("column2", columns23.getColumns().get(0)); - assertTrue(columns23.isColumnInGroup("column2")); - assertEquals("column3", columns23.getColumns().get(1)); - assertTrue(columns23.isColumnInGroup("column3")); - - // Combine groups - ColumnGroupRow row2 = grid.addColumnGroupRow(); - ColumnGroup columns0123 = row2.addGroup(columns01, columns23); - assertEquals(4, columns0123.getColumns().size()); - assertEquals("column0", columns0123.getColumns().get(0)); - assertTrue(columns0123.isColumnInGroup("column0")); - assertEquals("column1", columns0123.getColumns().get(1)); - assertTrue(columns0123.isColumnInGroup("column1")); - assertEquals("column2", columns0123.getColumns().get(2)); - assertTrue(columns0123.isColumnInGroup("column2")); - assertEquals("column3", columns0123.getColumns().get(3)); - assertTrue(columns0123.isColumnInGroup("column3")); - } - - @Test - public void testColumnGroupHeadersAndFooters() throws Exception { - - ColumnGroupRow row = grid.addColumnGroupRow(); - ColumnGroup group = row.addGroup("column1", "column2"); - - // Header - assertNull(group.getHeaderCaption()); - group.setHeaderCaption("My header"); - assertEquals("My header", group.getHeaderCaption()); - group.setHeaderCaption(null); - assertNull(group.getHeaderCaption()); - - // Footer - assertNull(group.getFooterCaption()); - group.setFooterCaption("My footer"); - assertEquals("My footer", group.getFooterCaption()); - group.setFooterCaption(null); - assertNull(group.getFooterCaption()); - } - - @Test - public void testColumnGroupDetachment() throws Exception { - - ColumnGroupRow row = grid.addColumnGroupRow(); - ColumnGroup group = row.addGroup("column1", "column2"); - - // Remove group - row.removeGroup(group); - - try { - group.setHeaderCaption("Header"); - fail("Should throw exception for setting header caption on detached group"); - } catch (IllegalStateException ise) { - - } - - try { - group.setFooterCaption("Footer"); - fail("Should throw exception for setting footer caption on detached group"); - } catch (IllegalStateException ise) { - - } - } - - @Test - public void testColumnGroupLimits() throws Exception { - - ColumnGroupRow row = grid.addColumnGroupRow(); - row.addGroup("column1", "column2"); - row.addGroup("column3", "column4"); - - try { - row.addGroup("column2", "column3"); - fail("Adding a group with already grouped properties should throw exception"); - } catch (IllegalArgumentException iae) { - - } - - ColumnGroupRow row2 = grid.addColumnGroupRow(); - - try { - row2.addGroup("column2", "column3"); - fail("Adding a group that breaks previous grouping boundaries should throw exception"); - } catch (IllegalArgumentException iae) { - - } - - // This however should not throw an exception as it spans completely - // over the parent rows groups - row2.addGroup("column1", "column2", "column3", "column4"); - - } -} diff --git a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java deleted file mode 100644 index d3d5ea2495..0000000000 --- a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2000-2013 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.vaadin.shared.ui.grid; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -/** - * The column group row data shared between the server and client - * - * @since - * @author Vaadin Ltd - */ -public class ColumnGroupRowState implements Serializable { - - /** - * The groups that has been added to the row - */ - public List groups = new ArrayList(); - - /** - * Is the header shown - */ - public boolean headerVisible = true; - - /** - * Is the footer shown - */ - public boolean footerVisible = false; - -} diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index 68ee64dfe4..54acc80127 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -102,11 +102,6 @@ public class GridState extends AbstractComponentState { public GridStaticSectionState footer = new GridStaticSectionState(); - /** - * The column groups added to the grid - */ - public List columnGroupRows = new ArrayList(); - /** * The id for the last frozen column. * diff --git a/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java b/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java deleted file mode 100644 index f1199301d9..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -/** - * - */ -package com.vaadin.tests.components.grid; - -import com.vaadin.data.util.IndexedContainer; -import com.vaadin.server.VaadinRequest; -import com.vaadin.tests.components.AbstractTestUI; -import com.vaadin.ui.components.grid.ColumnGroup; -import com.vaadin.ui.components.grid.ColumnGroupRow; -import com.vaadin.ui.components.grid.Grid; -import com.vaadin.ui.components.grid.GridColumn; - -public class GridColumnGroups extends AbstractTestUI { - - private final int COLUMNS = 4; - - @Override - protected void setup(VaadinRequest request) { - - // Setup grid - IndexedContainer ds = new IndexedContainer(); - for (int col = 0; col < COLUMNS; col++) { - ds.addContainerProperty("Column" + col, String.class, ""); - } - Grid grid = new Grid(ds); - addComponent(grid); - - /*- - * --------------------------------------------- - * | Header 1 | <- Auxiliary row 2 - * |-------------------------------------------| - * | Header 2 | Header 3 | <- Auxiliary row 1 - * |-------------------------------------------| - * | Column 1 | Column 2 | Column 3 | Column 4 | <- Column headers - * --------------------------------------------| - * | ... | ... | ... | ... | - * | ... | ... | ... | ... | - * --------------------------------------------| - * | Column 1 | Column 2 | Column 3 | Column 4 | <- Column footers - * --------------------------------------------| - * | Footer 2 | Footer 3 | <- Auxiliary row 1 - * --------------------------------------------| - * | Footer 1 | <- Auxiliary row 2 - * --------------------------------------------- - -*/ - - // Set column footers (headers are generated automatically) - grid.setColumnFootersVisible(true); - for (Object propertyId : ds.getContainerPropertyIds()) { - GridColumn column = grid.getColumn(propertyId); - column.setFooterCaption(String.valueOf(propertyId)); - } - - // First auxiliary row - ColumnGroupRow auxRow1 = grid.addColumnGroupRow(); - - // Using property id to create a column group - ColumnGroup columns12 = auxRow1.addGroup("Column0", "Column1"); - columns12.setHeaderCaption("Header 2"); - columns12.setFooterCaption("Footer 2"); - - // Using grid columns to create a column group - GridColumn column3 = grid.getColumn("Column2"); - GridColumn column4 = grid.getColumn("Column3"); - ColumnGroup columns34 = auxRow1.addGroup(column3, column4); - columns34.setHeaderCaption("Header 3"); - columns34.setFooterCaption("Footer 3"); - - // Second auxiliary row - ColumnGroupRow auxRow2 = grid.addColumnGroupRow(); - - // Using previous groups to create a column group - ColumnGroup columns1234 = auxRow2.addGroup(columns12, columns34); - columns1234.setHeaderCaption("Header 1"); - columns1234.setFooterCaption("Footer 1"); - - } - - @Override - protected String getTestDescription() { - return "Grid should support headers and footer groups"; - } - - @Override - protected Integer getTicketNumber() { - return 12894; - } - -} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index bff16d8db7..9ab2c98bdb 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -31,8 +31,6 @@ import com.vaadin.data.util.IndexedContainer; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.SortDirection; import com.vaadin.tests.components.AbstractComponentTest; -import com.vaadin.ui.components.grid.ColumnGroup; -import com.vaadin.ui.components.grid.ColumnGroupRow; import com.vaadin.ui.components.grid.Grid; import com.vaadin.ui.components.grid.Grid.SelectionMode; import com.vaadin.ui.components.grid.GridColumn; @@ -178,8 +176,6 @@ public class GridBasicFeatures extends AbstractComponentTest { createFooterActions(); - createColumnGroupActions(); - createRowActions(); addHeightActions(); @@ -451,72 +447,6 @@ public class GridBasicFeatures extends AbstractComponentTest { return "Column " + c; } - protected void createColumnGroupActions() { - createCategory("Column groups", null); - - createClickAction("Add group row", "Column groups", - new Command() { - - @Override - public void execute(Grid grid, String value, Object data) { - final ColumnGroupRow row = grid.addColumnGroupRow(); - columnGroupRows++; - createCategory("Column group row " + columnGroupRows, - "Column groups"); - - createBooleanAction("Header Visible", - "Column group row " + columnGroupRows, true, - new Command() { - - @Override - public void execute(Grid grid, - Boolean value, Object columnIndex) { - row.setHeaderVisible(value); - } - }, row); - - createBooleanAction("Footer Visible", - "Column group row " + columnGroupRows, false, - new Command() { - - @Override - public void execute(Grid grid, - Boolean value, Object columnIndex) { - row.setFooterVisible(value); - } - }, row); - - for (int i = 0; i < COLUMNS; i++) { - final int columnIndex = i; - createClickAction("Group Column " + columnIndex - + " & " + (columnIndex + 1), - "Column group row " + columnGroupRows, - new Command() { - - @Override - public void execute(Grid c, - Integer value, Object data) { - final ColumnGroup group = row - .addGroup( - "Column" + value, - "Column" - + (value + 1)); - - group.setHeaderCaption("Column " - + value + " & " - + (value + 1)); - - group.setFooterCaption("Column " - + value + " & " - + (value + 1)); - } - }, i, row); - } - } - }, null, null); - - } - protected void createRowActions() { createCategory("Body rows", null); -- cgit v1.2.3 From df68ce33bde680de12cdf6457311c35662252da2 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 30 Jul 2014 15:06:36 +0300 Subject: Add support for server side colspans in Headers and Footers (#13334) Change-Id: I311aade38f4e725405a190ca1b6f114b4ac07053 --- .../com/vaadin/client/ui/grid/FlyweightCell.java | 8 ++ client/src/com/vaadin/client/ui/grid/Grid.java | 7 +- .../com/vaadin/client/ui/grid/GridConnector.java | 19 +++- .../com/vaadin/ui/components/grid/GridFooter.java | 2 +- .../com/vaadin/ui/components/grid/GridHeader.java | 4 +- .../ui/components/grid/GridStaticSection.java | 109 +++++++++++++++++++-- .../server/component/grid/GridStaticSection.java | 105 ++++++++++++++++++++ .../shared/ui/grid/GridStaticSectionState.java | 2 + .../vaadin/tests/components/grid/GridColspans.java | 81 +++++++++++++++ .../tests/components/grid/GridColspansTest.java | 73 ++++++++++++++ .../vaadin/tests/components/grid/GridElement.java | 5 + 11 files changed, 403 insertions(+), 12 deletions(-) create mode 100644 server/tests/src/com/vaadin/tests/server/component/grid/GridStaticSection.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridColspans.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridColspansTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java index 17301214c8..de003f865c 100644 --- a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java +++ b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java @@ -78,6 +78,14 @@ public class FlyweightCell { return element; } + /** + * Return the colspan attribute of the element of the cell. + */ + public int getColSpan() { + assertSetup(); + return element.getPropertyInt(COLSPAN_ATTR); + } + /** * Sets the DOM element for this FlyweightCell, either a TD or * a TH. It is the caller's responsibility to actually insert diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index f800a8cb3b..f280b26493 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -123,10 +123,13 @@ public class Grid extends Composite implements RowContainer cellContainer) { int cellRow = cell.getRow(); int cellColumn = cell.getColumn(); + int colSpan = cell.getColSpan(); + boolean columnActive = Range.withLength(cellColumn, colSpan) + .contains(activeColumn); if (cellContainer == container) { // Cell is in the current container - if (cellRow == activeRow && cellColumn == activeColumn) { + if (cellRow == activeRow && columnActive) { if (cellWithActiveStyle != cell.getElement()) { // Cell is correct but it does not have active style if (cellWithActiveStyle != null) { @@ -152,7 +155,7 @@ public class Grid extends Composite implements || cellContainer == escalator.getFooter()) { // Correct header and footer column also needs highlighting setStyleName(cell.getElement(), headerFooterActiveStyleName, - cellColumn == activeColumn); + columnActive); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 2a06aba3e6..2bbedaaecf 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -36,11 +36,13 @@ import com.vaadin.client.data.DataSource.RowHandle; import com.vaadin.client.data.RpcDataSourceConnector.RpcDataSource; import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; +import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; import com.vaadin.client.ui.grid.GridStaticSection.StaticRow; import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; import com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel; import com.vaadin.client.ui.grid.selection.SelectionChangeEvent; import com.vaadin.client.ui.grid.selection.SelectionChangeHandler; +import com.vaadin.client.ui.grid.selection.SelectionModel; import com.vaadin.client.ui.grid.selection.SelectionModelMulti; import com.vaadin.client.ui.grid.selection.SelectionModelNone; import com.vaadin.client.ui.grid.selection.SelectionModelSingle; @@ -288,9 +290,24 @@ public class GridConnector extends AbstractComponentConnector { assert rowState.cells.size() == getWidget().getColumnCount(); + int diff = 1; + if (getWidget().getSelectionModel() instanceof SelectionModel.None) { + diff = 0; + } + int i = 0; for (CellState cellState : rowState.cells) { - row.getCell(i++).setText(cellState.text); + StaticCell cell = row.getCell(diff + (i++)); + cell.setText(cellState.text); + } + + for (List group : rowState.cellGroups) { + GridColumn[] columns = new GridColumn[group.size()]; + i = 0; + for (Integer colIndex : group) { + columns[i++] = getWidget().getColumn(diff + colIndex); + } + row.join(columns); } if (section instanceof GridHeader && rowState.defaultRow) { diff --git a/server/src/com/vaadin/ui/components/grid/GridFooter.java b/server/src/com/vaadin/ui/components/grid/GridFooter.java index e4a7eab5d1..84b2b70090 100644 --- a/server/src/com/vaadin/ui/components/grid/GridFooter.java +++ b/server/src/com/vaadin/ui/components/grid/GridFooter.java @@ -54,7 +54,7 @@ public class GridFooter extends GridStaticSection { } @Override - protected GridStaticSectionState getState() { + protected GridStaticSectionState getSectionState() { return footerState; } diff --git a/server/src/com/vaadin/ui/components/grid/GridHeader.java b/server/src/com/vaadin/ui/components/grid/GridHeader.java index f8bd3c6642..67f7bfdf69 100644 --- a/server/src/com/vaadin/ui/components/grid/GridHeader.java +++ b/server/src/com/vaadin/ui/components/grid/GridHeader.java @@ -57,7 +57,7 @@ public class GridHeader extends GridStaticSection { HeaderRow row = createRow(); rows.add(row); setDefaultRow(row); - getState().rows.add(row.getRowState()); + getSectionState().rows.add(row.getRowState()); } /** @@ -103,7 +103,7 @@ public class GridHeader extends GridStaticSection { } @Override - protected GridStaticSectionState getState() { + protected GridStaticSectionState getSectionState() { return headerState; } diff --git a/server/src/com/vaadin/ui/components/grid/GridStaticSection.java b/server/src/com/vaadin/ui/components/grid/GridStaticSection.java index 80d822e7bc..8c983052ea 100644 --- a/server/src/com/vaadin/ui/components/grid/GridStaticSection.java +++ b/server/src/com/vaadin/ui/components/grid/GridStaticSection.java @@ -17,6 +17,10 @@ package com.vaadin.ui.components.grid; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -49,6 +53,7 @@ abstract class GridStaticSection> private RowState rowState = new RowState(); protected GridStaticSection section; private Map cells = new LinkedHashMap(); + private Collection> cellGroups = new HashSet>(); protected StaticRow(GridStaticSection section) { this.section = section; @@ -83,6 +88,98 @@ abstract class GridStaticSection> public CELLTYPE getCell(Object propertyId) { return cells.get(propertyId); } + + /** + * Merges cells in a row + * + * @param cells + * The cells to be merged + * @return The first cell of the merged cells + */ + protected CELLTYPE join(List cells) { + assert cells.size() > 1 : "You cannot merge less than 2 cells together"; + + // Ensure no cell is already grouped + for (CELLTYPE cell : cells) { + if (getCellGroupForCell(cell) != null) { + throw new IllegalStateException("Cell " + cell.getText() + + " is already grouped."); + } + } + + // Ensure continuous range + Iterator cellIterator = this.cells.values().iterator(); + CELLTYPE current = null; + int firstIndex = 0; + + while (cellIterator.hasNext()) { + current = cellIterator.next(); + if (current == cells.get(0)) { + break; + } + firstIndex++; + } + + for (int i = 1; i < cells.size(); ++i) { + current = cellIterator.next(); + + if (current != cells.get(i)) { + throw new IllegalStateException( + "Cell range must be a continous range"); + } + } + + // Create a new group + final ArrayList cellGroup = new ArrayList(cells); + cellGroups.add(cellGroup); + + // Add group to state + List stateGroup = new ArrayList(); + for (int i = 0; i < cells.size(); ++i) { + stateGroup.add(firstIndex + i); + } + rowState.cellGroups.add(stateGroup); + section.markAsDirty(); + + // Returns first cell of group + return cells.get(0); + } + + /** + * Merges columns cells in a row + * + * @param properties + * The column properties which header should be merged + * @return The remaining visible cell after the merge + */ + public CELLTYPE join(Object... properties) { + List cells = new ArrayList(); + for (int i = 0; i < properties.length; ++i) { + cells.add(getCell(properties[i])); + } + + return join(cells); + } + + /** + * Merges columns cells in a row + * + * @param cells + * The cells to merge. Must be from the same row. + * @return The remaining visible cell after the merge + */ + public CELLTYPE join(CELLTYPE... cells) { + return join(Arrays.asList(cells)); + } + + private List getCellGroupForCell(CELLTYPE cell) { + for (List group : cellGroups) { + if (group.contains(cell)) { + return group; + } + } + return null; + } } /** @@ -148,8 +245,8 @@ abstract class GridStaticSection> * true to show this section, false to hide */ public void setVisible(boolean visible) { - if (getState().visible != visible) { - getState().visible = visible; + if (getSectionState().visible != visible) { + getSectionState().visible = visible; markAsDirty(); } } @@ -160,7 +257,7 @@ abstract class GridStaticSection> * @return true if visible, false otherwise. */ public boolean isVisible() { - return getState().visible; + return getSectionState().visible; } /** @@ -174,7 +271,7 @@ abstract class GridStaticSection> */ public ROWTYPE removeRow(int rowIndex) { ROWTYPE row = rows.remove(rowIndex); - getState().rows.remove(rowIndex); + getSectionState().rows.remove(rowIndex); markAsDirty(); return row; @@ -240,7 +337,7 @@ abstract class GridStaticSection> public ROWTYPE addRowAt(int index) { ROWTYPE row = createRow(); rows.add(index, row); - getState().rows.add(index, row.getRowState()); + getSectionState().rows.add(index, row.getRowState()); Indexed dataSource = grid.getContainerDatasource(); for (Object id : dataSource.getContainerPropertyIds()) { @@ -260,7 +357,7 @@ abstract class GridStaticSection> return rows.size(); } - protected abstract GridStaticSectionState getState(); + protected abstract GridStaticSectionState getSectionState(); protected abstract ROWTYPE createRow(); diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridStaticSection.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridStaticSection.java new file mode 100644 index 0000000000..e89f6a8c6e --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridStaticSection.java @@ -0,0 +1,105 @@ +/* + * 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.server.component.grid; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.data.Container.Indexed; +import com.vaadin.data.util.IndexedContainer; +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; + +public class GridStaticSection { + + private Indexed dataSource = new IndexedContainer(); + private Grid grid; + + @Before + public void setUp() { + dataSource.addContainerProperty("firstName", String.class, ""); + dataSource.addContainerProperty("lastName", String.class, ""); + dataSource.addContainerProperty("streetAddress", String.class, ""); + dataSource.addContainerProperty("zipCode", Integer.class, null); + grid = new Grid(dataSource); + } + + @Test + public void testAddAndRemoveHeaders() { + + final GridHeader section = grid.getHeader(); + assertEquals(1, section.getRowCount()); + section.prependRow(); + assertEquals(2, section.getRowCount()); + section.removeRow(0); + assertEquals(1, section.getRowCount()); + section.removeRow(0); + assertEquals(0, section.getRowCount()); + assertEquals(null, section.getDefaultRow()); + HeaderRow row = section.appendRow(); + assertEquals(1, section.getRowCount()); + assertEquals(null, section.getDefaultRow()); + section.setDefaultRow(row); + assertEquals(row, section.getDefaultRow()); + } + + @Test + public void testAddAndRemoveFooters() { + final GridFooter section = grid.getFooter(); + + // By default there are no footer rows + assertEquals(0, section.getRowCount()); + FooterRow row = section.appendRow(); + + assertEquals(1, section.getRowCount()); + section.prependRow(); + assertEquals(2, section.getRowCount()); + assertEquals(row, section.getRow(1)); + section.removeRow(0); + assertEquals(1, section.getRowCount()); + section.removeRow(0); + assertEquals(0, section.getRowCount()); + } + + @Test + public void testJoinHeaderCells() { + final GridHeader section = grid.getHeader(); + HeaderRow mergeRow = section.prependRow(); + mergeRow.join("firstName", "lastName").setText("Name"); + mergeRow.join(mergeRow.getCell("streetAddress"), + mergeRow.getCell("zipCode")); + } + + @Test(expected = IllegalStateException.class) + public void testJoinHeaderCellsIncorrectly() { + final GridHeader section = grid.getHeader(); + HeaderRow mergeRow = section.prependRow(); + mergeRow.join("firstName", "zipCode").setText("Name"); + } + + @Test + public void testJoinAllFooterrCells() { + final GridFooter section = grid.getFooter(); + FooterRow mergeRow = section.prependRow(); + mergeRow.join(dataSource.getContainerPropertyIds().toArray()).setText( + "All the stuff."); + } +} diff --git a/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java b/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java index 859e01f089..41f56199da 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java @@ -35,6 +35,8 @@ public class GridStaticSectionState implements Serializable { public List cells = new ArrayList(); public boolean defaultRow = false; + + public List> cellGroups = new ArrayList>(); } public List rows = new ArrayList(); 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..be12c2bcb2 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridColspans.java @@ -0,0 +1,81 @@ +/* + * 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"); + + footer.setVisible(true); + } + + @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 index 5027c603d9..3b28c4eaa2 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridElement.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridElement.java @@ -38,10 +38,15 @@ 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"; public boolean isActive() { return getAttribute("class").contains(ACTIVE_CLASS_NAME); } + + public boolean isActiveHeader() { + return getAttribute("class").contains(ACTIVE_HEADER_CLASS_NAME); + } } public static class GridRowElement extends AbstractElement { -- cgit v1.2.3 From 9d051687d1f39690c356aa3f916c0dc900cb9af0 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Tue, 5 Aug 2014 13:58:00 +0300 Subject: Trigger ComplexRenderer.setContentVisible(false) initially #13334 Change-Id: Id2ebb2f7f6c0480ab6353df0ae87fea3b1153ea0 --- client/src/com/vaadin/client/ui/grid/Grid.java | 2 +- .../tests/components/grid/GridClientRenderers.java | 24 ++++++++++++++++------ .../grid/GridClientColumnRendererConnector.java | 7 ++++++- 3 files changed, 25 insertions(+), 8 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index a32a31b029..cff9f68454 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -1238,7 +1238,7 @@ public class Grid extends Composite implements Object value = column.getValue(rowData); clxRenderer.render(cell, value); - } else if (usedToHaveData) { + } else { // Prepare cell for no data clxRenderer.setContentVisible(cell, false); } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index d1aec66dbd..fd3c8d5b2f 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -17,6 +17,7 @@ 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; @@ -80,7 +81,7 @@ public class GridClientRenderers extends MultiBrowserTest { $(NativeButtonElement.class).caption("Add").first().click(); // Click the button in cell 1,1 - TestBenchElement cell = getGrid().getCell(1, 1); + TestBenchElement cell = getGrid().getCell(1, 2); WebElement gwtButton = cell.findElement(By.tagName("button")); gwtButton.click(); @@ -102,7 +103,7 @@ public class GridClientRenderers extends MultiBrowserTest { $(NativeButtonElement.class).caption("DetachAttach").first().click(); // Click the button in cell 1,1 - TestBenchElement cell = getGrid().getCell(1, 1); + TestBenchElement cell = getGrid().getCell(1, 2); WebElement gwtButton = cell.findElement(By.tagName("button")); gwtButton.click(); @@ -159,17 +160,28 @@ public class GridClientRenderers extends MultiBrowserTest { openTestURL(); - addColumn(Renderers.CPLX_RENDERER); + // 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) - TestBenchElement cell = getGrid().getCell(51, 1); - String backgroundColor = cell.getCssValue("backgroundColor"); + cell = getGrid().getCell(55, 1); + backgroundColor = cell.getCssValue("backgroundColor"); assertEquals("Background color was not red.", colorRed, backgroundColor); - // Wait for data to arrive + // data arrives... sleep((int) (latency * SLEEP_MULTIPLIER)); // Cell should no longer be red diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index e685034c7b..c0e57e97aa 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -64,7 +64,7 @@ public class GridClientColumnRendererConnector extends private class DelayedDataSource implements DataSource { private DataSource ds; - private int firstRowIndex; + private int firstRowIndex = -1; private int numberOfRows; private DataChangeHandler dataChangeHandler; private int latency; @@ -139,6 +139,11 @@ public class GridClientColumnRendererConnector extends grid.addColumn(c); grid.getHeader().getDefaultRow().getCell(0).setText("Column 1"); + // Add another column with a custom complex renderer + c = createColumnWithRenderer(Renderers.CPLX_RENDERER); + grid.addColumn(c); + grid.getHeader().getDefaultRow().getCell(1).setText("Column 2"); + // Add method for testing sort event firing grid.addSortHandler(new SortEventHandler() { @Override -- cgit v1.2.3 From a9fc5d5be75c8ca33231909d1a44f471b5dcaaf9 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Thu, 7 Aug 2014 11:11:03 +0300 Subject: Fixes removing all rows causing javascript error #13334 Change-Id: If3850d2248c6731bf3ee55d73c4cba2999ff9882 --- shared/src/com/vaadin/shared/ui/grid/Range.java | 6 ++++++ .../tests/components/grid/basicfeatures/GridBasicFeatures.java | 9 +++++++++ .../tests/components/grid/basicfeatures/GridStructureTest.java | 10 ++++++++++ 3 files changed, 25 insertions(+) (limited to 'uitest/src') diff --git a/shared/src/com/vaadin/shared/ui/grid/Range.java b/shared/src/com/vaadin/shared/ui/grid/Range.java index a1d4d86103..38b2ff2a60 100644 --- a/shared/src/com/vaadin/shared/ui/grid/Range.java +++ b/shared/src/com/vaadin/shared/ui/grid/Range.java @@ -369,6 +369,12 @@ public final class Range implements Serializable { * if the two ranges aren't connected */ public Range combineWith(Range other) throws IllegalArgumentException { + if (other.isEmpty()) { + return this; + } else if (isEmpty()) { + return other; + } + if (getStart() > other.getEnd() || other.getStart() > getEnd()) { throw new IllegalArgumentException("There is a gap between " + this + " and " + other); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 9ab2c98bdb..8b3391253b 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -521,6 +521,15 @@ public class GridBasicFeatures extends AbstractComponentTest { } } }); + + createClickAction("Remove all rows", "Body rows", + new Command() { + @SuppressWarnings("unchecked") + @Override + public void execute(Grid c, String value, Object data) { + ds.removeAllItems(); + } + }, null); } @SuppressWarnings("boxing") diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java index ced6963c32..d52f512b4f 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java @@ -197,6 +197,16 @@ public class GridStructureTest extends GridBasicFeaturesTest { "modified: Column 0", getBodyCellByRowAndColumn(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()); + } + private void assertPrimaryStylename(String stylename) { assertTrue(getGridElement().getAttribute("class").contains(stylename)); -- cgit v1.2.3 From a479a22f20d683b794350a7098abe78835c495b5 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Mon, 4 Aug 2014 14:38:12 +0300 Subject: Take hidden columns into account when calculating colspan #13334 Change-Id: Ibaf5950408dfbd832efcca6882db94258f2e9b3a --- .../com/vaadin/client/ui/grid/FlyweightCell.java | 5 ++ client/src/com/vaadin/client/ui/grid/Grid.java | 11 +++- .../src/com/vaadin/client/ui/grid/GridFooter.java | 22 +++++++- .../src/com/vaadin/client/ui/grid/GridHeader.java | 21 ++++++- .../vaadin/client/ui/grid/GridStaticSection.java | 57 ++++++++++++++++--- .../grid/basicfeatures/GridHeaderTest.java | 65 ++++++++++++++++++++++ .../client/grid/GridBasicClientFeatures.java | 10 ++++ 7 files changed, 180 insertions(+), 11 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java index de003f865c..b82fccfbe0 100644 --- a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java +++ b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java @@ -144,6 +144,11 @@ public class FlyweightCell { } public void setColSpan(final int numberOfCells) { + if (numberOfCells < 1) { + throw new IllegalArgumentException( + "Number of cells should be more than 0"); + } + /*- * This will default to 1 if unset, as per DOM specifications: * http://www.w3.org/TR/html5/tabular-data.html#attributes-common-to-td-and-th-elements diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index cff9f68454..580cf41165 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -45,6 +45,7 @@ import com.vaadin.client.Util; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.SubPartAware; +import com.vaadin.client.ui.grid.GridFooter.FooterRow; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; @@ -923,7 +924,6 @@ public class Grid extends Composite implements this.visible = visible; - // Remove column if (grid != null) { int index = findIndexOfColumn(); ColumnConfiguration conf = grid.escalator @@ -934,8 +934,15 @@ public class Grid extends Composite implements } else { conf.removeColumns(index, 1); } - } + for (HeaderRow row : grid.getHeader().getRows()) { + row.calculateColspans(); + } + + for (FooterRow row : grid.getFooter().getRows()) { + row.calculateColspans(); + } + } } /** diff --git a/client/src/com/vaadin/client/ui/grid/GridFooter.java b/client/src/com/vaadin/client/ui/grid/GridFooter.java index eba6ad81cb..4470bbf6b9 100644 --- a/client/src/com/vaadin/client/ui/grid/GridFooter.java +++ b/client/src/com/vaadin/client/ui/grid/GridFooter.java @@ -15,6 +15,8 @@ */ package com.vaadin.client.ui.grid; +import com.google.gwt.core.client.Scheduler; + /** * Represents the footer section of a Grid. The footer is always empty. * @@ -50,6 +52,8 @@ public class GridFooter extends GridStaticSection { public class FooterCell extends GridStaticSection.StaticCell { } + private boolean markAsDirty = false; + @Override protected FooterRow createRow() { return new FooterRow(); @@ -57,6 +61,22 @@ public class GridFooter extends GridStaticSection { @Override protected void refreshSection() { - getGrid().refreshFooter(); + markAsDirty = true; + + /* + * Defer the refresh so if we multiple times call refreshSection() (for + * example when updating cell values) we only get one actual refresh in + * the end. + */ + Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() { + + @Override + public void execute() { + if (markAsDirty) { + markAsDirty = false; + getGrid().refreshFooter(); + } + } + }); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridHeader.java b/client/src/com/vaadin/client/ui/grid/GridHeader.java index 4e046873f4..e139d7b946 100644 --- a/client/src/com/vaadin/client/ui/grid/GridHeader.java +++ b/client/src/com/vaadin/client/ui/grid/GridHeader.java @@ -15,6 +15,7 @@ */ package com.vaadin.client.ui.grid; +import com.google.gwt.core.client.Scheduler; import com.vaadin.client.ui.grid.Grid.AbstractGridColumn.SortableColumnHeaderRenderer; /** @@ -68,6 +69,8 @@ public class GridHeader extends GridStaticSection { private HeaderRow defaultRow; + private boolean markAsDirty = false; + @Override public void removeRow(int index) { HeaderRow removedRow = getRow(index); @@ -134,6 +137,22 @@ public class GridHeader extends GridStaticSection { @Override protected void refreshSection() { - getGrid().refreshHeader(); + markAsDirty = true; + + /* + * Defer the refresh so if we multiple times call refreshSection() (for + * example when updating cell values) we only get one actual refresh in + * the end. + */ + Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() { + + @Override + public void execute() { + if (markAsDirty) { + markAsDirty = false; + getGrid().refreshHeader(); + } + } + }); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index fa4f3e5ea0..c40c41594c 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -85,11 +85,18 @@ abstract class GridStaticSection> } /** + * Sets the colspan for the cell + * * @param colspan * the colspan to set */ public void setColspan(int colspan) { + if (colspan < 1) { + throw new IllegalArgumentException( + "Colspan cannot be less than 1"); + } this.colspan = colspan; + section.refreshSection(); } } @@ -201,7 +208,8 @@ abstract class GridStaticSection> return null; } - private void calculateColspans() { + void calculateColspans() { + // Reset all cells for (CELLTYPE cell : cells) { cell.setColspan(1); @@ -209,17 +217,52 @@ abstract class GridStaticSection> // Set colspan for grouped cells for (List group : cellGroups) { + + int firstVisibleColumnInGroup = -1; + int lastVisibleColumnInGroup = -1; + int hiddenInsideGroup = 0; + + /* + * To be able to calculate the colspan correctly we need to two + * things; find the first visible cell in the group which will + * get the colspan assigned to and find the amount of columns + * which should be spanned. + * + * To do that we iterate through all cells, marking into memory + * when we find the first visible cell, when we find the last + * visible cell and how many cells are hidden in between. + */ for (int i = 0; i < group.size(); i++) { CELLTYPE cell = group.get(i); - if (i == 0) { - // Assign full colspan to first cell - cell.setColspan(group.size()); - } else { - // Hide other cells - cell.setColspan(0); + int cellIndex = this.cells.indexOf(cell); + boolean columnVisible = getSection().getGrid() + .getColumn(cellIndex).isVisible(); + if (columnVisible) { + lastVisibleColumnInGroup = i; + if (firstVisibleColumnInGroup == -1) { + firstVisibleColumnInGroup = i; + } + } else if (firstVisibleColumnInGroup != -1) { + hiddenInsideGroup++; } } + + if (firstVisibleColumnInGroup == -1 + || lastVisibleColumnInGroup == -1 + || firstVisibleColumnInGroup == lastVisibleColumnInGroup) { + // No cells in group + continue; + } + + /* + * Assign colspan to first cell in group. + */ + CELLTYPE firstVisibleCell = group + .get(firstVisibleColumnInGroup); + firstVisibleCell.setColspan(lastVisibleColumnInGroup + - firstVisibleColumnInGroup - hiddenInsideGroup + 1); } + } protected void addCell(int index) { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java index 43d5aa47df..2665d5c669 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java @@ -211,6 +211,71 @@ public class GridHeaderTest extends GridStaticSectionTest { } } + @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")); + } + private void assertHeaderCount(int count) { assertEquals("header count", count, getGridElement().getHeaderCount()); } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index 1c9758b669..24cfe49239 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -396,6 +396,16 @@ public class GridBasicClientFeatures extends } }, 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 -- cgit v1.2.3 From 94dfb5d68dd6c1e3542edc80488fe53a9da2d0e5 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Wed, 30 Jul 2014 13:27:51 +0300 Subject: Support HTML and Widgets in header/footer cells #13334 Change-Id: I1f9a4388b9b2e9e3892b31977eaf674ed4e0959b --- .../src/com/vaadin/client/ui/grid/Escalator.java | 8 +- client/src/com/vaadin/client/ui/grid/Grid.java | 82 +++++++++++-- .../com/vaadin/client/ui/grid/GridConnector.java | 2 +- .../src/com/vaadin/client/ui/grid/GridFooter.java | 10 +- .../src/com/vaadin/client/ui/grid/GridHeader.java | 14 +-- .../vaadin/client/ui/grid/GridStaticSection.java | 135 ++++++++++++++++++--- .../grid/basicfeatures/GridFooterTest.java | 59 +++++++++ .../grid/basicfeatures/GridHeaderTest.java | 79 +++++++++++- .../grid/basicfeatures/GridStaticSectionTest.java | 40 +++++- .../client/grid/GridBasicClientFeatures.java | 88 +++++++++++++- 10 files changed, 460 insertions(+), 57 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index df564be937..7263313356 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -4405,7 +4405,13 @@ public class Escalator extends Widget { @SuppressWarnings("deprecation") com.google.gwt.user.client.Element castElement = (com.google.gwt.user.client.Element) possibleWidgetNode .cast(); - return Util.findWidget(castElement, null); + Widget w = Util.findWidget(castElement, null); + + // Ensure findWidget did not traverse past the cell element in the + // DOM hierarchy + if (cellNode.isOrHasChild(w.getElement())) { + return w; + } } return null; } diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 580cf41165..cf0606a38c 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -710,7 +710,7 @@ public class Grid extends Composite implements public Collection getConsumedEvents() { return Arrays.asList(BrowserEvents.TOUCHSTART, BrowserEvents.TOUCHMOVE, BrowserEvents.TOUCHEND, - BrowserEvents.TOUCHCANCEL, BrowserEvents.MOUSEDOWN); + BrowserEvents.TOUCHCANCEL, BrowserEvents.CLICK); } @Override @@ -774,11 +774,14 @@ public class Grid extends Composite implements lazySorter.cancel(); - } else if (BrowserEvents.MOUSEDOWN.equals(event.getType())) { - event.preventDefault(); + } else if (BrowserEvents.CLICK.equals(event.getType())) { lazySorter.setCurrentCell(cell); lazySorter.setMultisort(event.getShiftKey()); lazySorter.run(); + + // Active cell handling is also monitoring the click + // event so we allow event to propagate for it + return false; } return true; } @@ -1046,7 +1049,7 @@ public class Grid extends Composite implements @Override public void update(Row row, Iterable cellsToUpdate) { - GridStaticSection.StaticRow gridRow = section.getRow(row + GridStaticSection.StaticRow staticRow = section.getRow(row .getRow()); final List columnIndices = getVisibleColumnIndices(); @@ -1054,13 +1057,28 @@ public class Grid extends Composite implements for (FlyweightCell cell : cellsToUpdate) { int index = columnIndices.get(cell.getColumn()); - StaticCell metadata = gridRow.getCell(index); + final StaticCell metadata = staticRow.getCell(index); // Assign colspan to cell before rendering cell.setColSpan(metadata.getColspan()); - // Render - gridRow.getRenderer().render(cell, metadata.getText()); + // Decorates cell with possible indicators onto the cell. + // Actual content is rendered below. + staticRow.getRenderer().render(cell, null); + + switch (metadata.getType()) { + case TEXT: + cell.getElement().setInnerText(metadata.getText()); + break; + case HTML: + cell.getElement().setInnerHTML(metadata.getHtml()); + break; + case WIDGET: + preDetach(row, Arrays.asList(cell)); + cell.getElement().setInnerHTML(""); + postAttach(row, Arrays.asList(cell)); + break; + } activeCellHandler.updateActiveCellStyle(cell, container); } @@ -1072,10 +1090,60 @@ public class Grid extends Composite implements @Override public void postAttach(Row row, Iterable attachedCells) { + GridStaticSection.StaticRow gridRow = section.getRow(row + .getRow()); + List columnIndices = getVisibleColumnIndices(); + + for (FlyweightCell cell : attachedCells) { + int index = columnIndices.get(cell.getColumn()); + StaticCell metadata = gridRow.getCell(index); + /* + * If the cell contains widgets that are not currently attach + * then attach them now. + */ + if (StaticCell.Type.WIDGET.equals(metadata.getType())) { + final Widget widget = metadata.getWidget(); + final Element cellElement = cell.getElement(); + + if (!widget.isAttached()) { + + // Physical attach + cellElement.appendChild(widget.getElement()); + + // Logical attach + setParent(widget, Grid.this); + + getLogger().info("Attached widget " + widget); + } + } + } } @Override public void preDetach(Row row, Iterable cellsToDetach) { + if (section.getRowCount() > row.getRow()) { + GridStaticSection.StaticRow gridRow = section.getRow(row + .getRow()); + List columnIndices = getVisibleColumnIndices(); + for (FlyweightCell cell : cellsToDetach) { + int index = columnIndices.get(cell.getColumn()); + StaticCell metadata = gridRow.getCell(index); + + if (StaticCell.Type.WIDGET.equals(metadata.getType()) + && metadata.getWidget().isAttached()) { + + Widget widget = metadata.getWidget(); + + // Logical detach + setParent(widget, null); + + // Physical detach + widget.getElement().removeFromParent(); + + getLogger().info("Detached widget " + widget); + } + } + } } @Override diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 039e3b1074..56affc75d1 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -317,7 +317,7 @@ public class GridConnector extends AbstractComponentConnector { section.setVisible(state.visible); - section.refreshSection(); + section.requestSectionRefresh(); } /** diff --git a/client/src/com/vaadin/client/ui/grid/GridFooter.java b/client/src/com/vaadin/client/ui/grid/GridFooter.java index 4470bbf6b9..e798139b9a 100644 --- a/client/src/com/vaadin/client/ui/grid/GridFooter.java +++ b/client/src/com/vaadin/client/ui/grid/GridFooter.java @@ -20,14 +20,6 @@ import com.google.gwt.core.client.Scheduler; /** * Represents the footer section of a Grid. The footer is always empty. * - * TODO Arbitrary number of footer rows (zero by default) - * - * TODO Merging footer cells - * - * TODO Widgets in cells - * - * TODO HTML in cells - * * @since * @author Vaadin Ltd */ @@ -60,7 +52,7 @@ public class GridFooter extends GridStaticSection { } @Override - protected void refreshSection() { + protected void requestSectionRefresh() { markAsDirty = true; /* diff --git a/client/src/com/vaadin/client/ui/grid/GridHeader.java b/client/src/com/vaadin/client/ui/grid/GridHeader.java index e139d7b946..f714848618 100644 --- a/client/src/com/vaadin/client/ui/grid/GridHeader.java +++ b/client/src/com/vaadin/client/ui/grid/GridHeader.java @@ -23,16 +23,6 @@ import com.vaadin.client.ui.grid.Grid.AbstractGridColumn.SortableColumnHeaderRen * row containing a header cell for each column. Each cell has a simple textual * caption. * - * TODO Arbitrary number of header rows (zero included, one by default) - * - * TODO Account for hidden columns when merging header cells - * - * TODO "Default" row with sorting - * - * TODO Widgets in cells - * - * TODO HTML in cells - * * @since * @author Vaadin Ltd */ @@ -117,7 +107,7 @@ public class GridHeader extends GridStaticSection { row.setDefault(true); } defaultRow = row; - refreshSection(); + requestSectionRefresh(); } /** @@ -136,7 +126,7 @@ public class GridHeader extends GridStaticSection { } @Override - protected void refreshSection() { + protected void requestSectionRefresh() { markAsDirty = true; /* diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index c40c41594c..14e4d6de9c 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -21,7 +21,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; -import com.vaadin.client.ui.grid.renderers.TextRenderer; +import com.google.gwt.user.client.ui.Widget; /** * Abstract base class for Grid header and footer sections. @@ -36,18 +36,21 @@ abstract class GridStaticSection> /** * A header or footer cell. Has a simple textual caption. * - * TODO HTML content - * - * TODO Widget content */ static class StaticCell { - private String text = ""; + public enum Type { + TEXT, HTML, WIDGET; + } + + private Object content = null; private int colspan = 1; private GridStaticSection section; + private Type type = Type.TEXT; + /** * Sets the text displayed in this cell. * @@ -55,8 +58,9 @@ abstract class GridStaticSection> * a plain text caption */ public void setText(String text) { - this.text = text; - section.refreshSection(); + this.content = text; + this.type = Type.TEXT; + section.requestSectionRefresh(); } /** @@ -65,7 +69,11 @@ abstract class GridStaticSection> * @return the plain text caption */ public String getText() { - return text; + if (type != Type.TEXT) { + throw new IllegalStateException( + "Cannot fetch Text from a cell with type " + type); + } + return (String) content; } protected GridStaticSection getSection() { @@ -78,14 +86,17 @@ abstract class GridStaticSection> } /** - * @return the colspan + * Returns the amount of columns the cell spans. By default is 1. + * + * @return The amount of columns the cell spans. */ public int getColspan() { return colspan; } /** - * Sets the colspan for the cell + * Sets the amount of columns the cell spans. Must be more or equal to + * 1. By default is 1. * * @param colspan * the colspan to set @@ -95,10 +106,78 @@ abstract class GridStaticSection> throw new IllegalArgumentException( "Colspan cannot be less than 1"); } + this.colspan = colspan; - section.refreshSection(); + section.requestSectionRefresh(); + } + + /** + * Returns the html inside the cell. + * + * @throws IllegalStateException + * if trying to retrive HTML from a cell with a type other + * than {@link Type#HTML}. + * @return the html content of the cell. + */ + public String getHtml() { + if (type != Type.HTML) { + throw new IllegalStateException( + "Cannot fetch HTML from a cell with type " + type); + } + return (String) content; } + /** + * Sets the content of the cell to the provided html. All previous + * content is discarded and the cell type is set to {@link Type#HTML}. + * + * @param html + * The html content of the cell + */ + public void setHtml(String html) { + this.content = html; + this.type = Type.HTML; + section.requestSectionRefresh(); + } + + /** + * Returns the widget in the cell. + * + * @throws IllegalStateException + * if the cell is not {@link Type#WIDGET} + * + * @return the widget in the cell + */ + public Widget getWidget() { + if (type != Type.WIDGET) { + throw new IllegalStateException( + "Cannot fetch Widget from a cell with type " + type); + } + return (Widget) content; + } + + /** + * Set widget as the content of the cell. The type of the cell becomes + * {@link Type#WIDGET}. All previous content is discarded. + * + * @param widget + * The widget to add to the cell. Should not be previously + * attached anywhere (widget.getParent == null). + */ + public void setWidget(Widget widget) { + this.content = widget; + this.type = Type.WIDGET; + section.requestSectionRefresh(); + } + + /** + * Returns the type of the cell. + * + * @return the type of content the cell contains. + */ + public Type getType() { + return type; + } } /** @@ -111,7 +190,16 @@ abstract class GridStaticSection> private List cells = new ArrayList(); - private Renderer renderer = new TextRenderer(); + private Renderer renderer = new Renderer() { + + @Override + public void render(FlyweightCell cell, String data) { + /* + * The rendering into the cell is done directly from the updater + * since it needs to handle multiple types of data. + */ + } + }; private GridStaticSection section; @@ -160,10 +248,9 @@ abstract class GridStaticSection> // Create a new group cellGroups.add(new ArrayList(cells)); + // Calculates colspans, triggers refresh on section implicitly calculateColspans(); - getSection().refreshSection(); - // Returns first cell of group return cells.get(0); } @@ -309,8 +396,12 @@ abstract class GridStaticSection> /** * Informs the grid that this section should be re-rendered. + *

+ * Note that re-render means calling update() on each cell, + * preAttach()/postAttach()/preDetach()/postDetach() is not called as the + * cells are not removed from the DOM. */ - protected abstract void refreshSection(); + protected abstract void requestSectionRefresh(); /** * Sets the visibility of the whole section. @@ -320,7 +411,7 @@ abstract class GridStaticSection> */ public void setVisible(boolean visible) { this.visible = visible; - refreshSection(); + requestSectionRefresh(); } /** @@ -349,7 +440,8 @@ abstract class GridStaticSection> row.addCell(i); } rows.add(index, row); - refreshSection(); + + requestSectionRefresh(); return row; } @@ -382,7 +474,7 @@ abstract class GridStaticSection> */ public void removeRow(int index) { rows.remove(index); - refreshSection(); + requestSectionRefresh(); } /** @@ -414,7 +506,12 @@ abstract class GridStaticSection> * if the index is out of bounds */ public ROWTYPE getRow(int index) { - return rows.get(index); + try { + return rows.get(index); + } catch (IndexOutOfBoundsException e) { + throw new IllegalArgumentException("Row with index " + index + + " does not exist"); + } } /** diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java index c4e86369f9..d6a865ee29 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java @@ -17,9 +17,12 @@ package com.vaadin.tests.components.grid.basicfeatures; 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; @@ -141,6 +144,62 @@ public class GridFooterTest extends GridStaticSectionTest { } } + @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("Footer (0,2)", 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("HTML Footer", 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/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java index 2665d5c669..ccffee854a 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java @@ -17,12 +17,15 @@ package com.vaadin.tests.components.grid.basicfeatures; 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; @@ -72,8 +75,8 @@ public class GridHeaderTest extends GridStaticSectionTest { assertEquals(GridBasicFeatures.COLUMNS - 2, cells.size()); assertText("Header (0,0)", cells.get(0)); - assertText("Header (0,2)", cells.get(1)); - assertText("Header (0,4)", cells.get(2)); + assertHTML("Header (0,2)", cells.get(1)); + assertHTML("Header (0,4)", cells.get(2)); selectMenuPath("Component", "Columns", "Column 3", "Visible"); @@ -81,9 +84,9 @@ public class GridHeaderTest extends GridStaticSectionTest { assertEquals(GridBasicFeatures.COLUMNS - 1, cells.size()); assertText("Header (0,0)", cells.get(0)); - assertText("Header (0,2)", cells.get(1)); + assertHTML("Header (0,2)", cells.get(1)); assertText("Header (0,3)", cells.get(2)); - assertText("Header (0,4)", cells.get(3)); + assertHTML("Header (0,4)", cells.get(3)); } @Test @@ -274,6 +277,74 @@ public class GridHeaderTest extends GridStaticSectionTest { 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("Header (0,2)", 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("HTML Header", 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) { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java index 8f6739e16d..5fac9cf860 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java @@ -30,7 +30,18 @@ public abstract class GridStaticSectionTest extends GridBasicClientFeaturesTest protected void assertHeaderTexts(int headerId, int rowIndex) { int i = 0; for (TestBenchElement cell : getGridElement().getHeaderCells(rowIndex)) { - assertText(String.format("Header (%d,%d)", headerId, i), cell); + + if (i % 3 == 0) { + assertText(String.format("Header (%d,%d)", headerId, i), cell); + } else if (i % 2 == 0) { + assertHTML(String.format("Header (%d,%d)", headerId, i), + cell); + } else { + assertHTML(String.format( + "

Header (%d,%d)
", + headerId, i), cell); + } + i++; } assertEquals("number of header columns", GridBasicFeatures.COLUMNS, i); @@ -39,7 +50,16 @@ public abstract class GridStaticSectionTest extends GridBasicClientFeaturesTest protected void assertFooterTexts(int footerId, int rowIndex) { int i = 0; for (TestBenchElement cell : getGridElement().getFooterCells(rowIndex)) { - assertText(String.format("Footer (%d,%d)", footerId, i), cell); + if (i % 3 == 0) { + assertText(String.format("Footer (%d,%d)", footerId, i), cell); + } else if (i % 2 == 0) { + assertHTML(String.format("Footer (%d,%d)", footerId, i), + cell); + } else { + assertHTML(String.format( + "
Footer (%d,%d)
", + footerId, i), cell); + } i++; } assertEquals("number of footer columns", GridBasicFeatures.COLUMNS, i); @@ -49,4 +69,20 @@ public abstract class GridStaticSectionTest extends GridBasicClientFeaturesTest // 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/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index 24cfe49239..50f60f9847 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -21,6 +21,10 @@ import java.util.List; import java.util.Random; import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.HTML; import com.vaadin.client.ui.grid.FlyweightCell; import com.vaadin.client.ui.grid.Grid; import com.vaadin.client.ui.grid.Grid.SelectionMode; @@ -277,6 +281,7 @@ public class GridBasicClientFeatures extends !grid.getColumn(index).isSortable()); } }, "Component", "Columns", "Column " + i); + addMenuCommand("auto", new ScheduledCommand() { @Override public void execute() { @@ -295,6 +300,66 @@ public class GridBasicClientFeatures extends grid.getColumn(index).setWidth(200); } }, "Component", "Columns", "Column " + i, "Width"); + + // Header types + addMenuCommand("Text Header", new ScheduledCommand() { + @Override + public void execute() { + grid.getHeader().getRow(0).getCell(index) + .setText("Text Header"); + } + }, "Component", "Columns", "Column " + i, "Header Type"); + addMenuCommand("HTML Header", new ScheduledCommand() { + @Override + public void execute() { + grid.getHeader().getRow(0).getCell(index) + .setHtml("HTML Header"); + } + }, "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(index).setWidget(button); + } + }, "Component", "Columns", "Column " + i, "Header Type"); + + // Footer types + addMenuCommand("Text Footer", new ScheduledCommand() { + @Override + public void execute() { + grid.getFooter().getRow(0).getCell(index) + .setText("Text Footer"); + } + }, "Component", "Columns", "Column " + i, "Footer Type"); + addMenuCommand("HTML Footer", new ScheduledCommand() { + @Override + public void execute() { + grid.getFooter().getRow(0).getCell(index) + .setHtml("HTML Footer"); + } + }, "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(index).setWidget(button); + } + }, "Component", "Columns", "Column " + i, "Footer Type"); } } @@ -303,14 +368,32 @@ public class GridBasicClientFeatures extends private void setHeaderTexts(HeaderRow row) { for (int i = 0; i < COLUMNS; ++i) { - row.getCell(i).setText("Header (" + headerCounter + "," + i + ")"); + String caption = "Header (" + headerCounter + "," + i + ")"; + + // Lets use some different cell types + if (i % 3 == 0) { + row.getCell(i).setText(caption); + } else if (i % 2 == 0) { + row.getCell(i).setHtml("" + caption + ""); + } else { + row.getCell(i).setWidget(new HTML(caption)); + } } headerCounter++; } private void setFooterTexts(FooterRow row) { for (int i = 0; i < COLUMNS; ++i) { - row.getCell(i).setText("Footer (" + footerCounter + "," + i + ")"); + String caption = "Footer (" + footerCounter + "," + i + ")"; + + // Lets use some different cell types + if (i % 3 == 0) { + row.getCell(i).setText(caption); + } else if (i % 2 == 0) { + row.getCell(i).setHtml("" + caption + ""); + } else { + row.getCell(i).setWidget(new HTML(caption)); + } } footerCounter++; } @@ -449,6 +532,7 @@ public class GridBasicClientFeatures extends addMenuCommand("Remove bottom row", new ScheduledCommand() { @Override public void execute() { + assert footer.getRowCount() > 0; footer.removeRow(footer.getRowCount() - 1); } }, menuPath); -- cgit v1.2.3 From c8e0335ccd4e2af54efe752fc98b20c52fafabcf Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Fri, 1 Aug 2014 15:07:30 +0300 Subject: Add server side support for Components in Headers and Footers (#13334) Change-Id: Ic5a6b4c68bc2d09840cbd7faffebae8991a5fff4 --- client/src/com/vaadin/client/ui/grid/Grid.java | 5 +- .../com/vaadin/client/ui/grid/GridConnector.java | 42 +++++++++- .../vaadin/client/ui/grid/GridStaticSection.java | 21 +++-- server/src/com/vaadin/ui/components/grid/Grid.java | 38 ++++++++- .../com/vaadin/ui/components/grid/GridFooter.java | 2 +- .../com/vaadin/ui/components/grid/GridHeader.java | 2 +- .../ui/components/grid/GridStaticSection.java | 93 +++++++++++++++++----- .../vaadin/shared/ui/grid/GridStaticCellType.java | 39 +++++++++ .../shared/ui/grid/GridStaticSectionState.java | 8 ++ .../grid/basicfeatures/GridBasicFeatures.java | 88 ++++++++++++++++++++ .../GridStaticSectionComponentTest.java | 56 +++++++++++++ 11 files changed, 354 insertions(+), 40 deletions(-) create mode 100644 shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index cf0606a38c..d1858a8f3f 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -62,6 +62,7 @@ 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.grid.GridConstants; +import com.vaadin.shared.ui.grid.GridStaticCellType; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.Range; import com.vaadin.shared.ui.grid.ScrollDestination; @@ -1101,7 +1102,7 @@ public class Grid extends Composite implements * If the cell contains widgets that are not currently attach * then attach them now. */ - if (StaticCell.Type.WIDGET.equals(metadata.getType())) { + if (GridStaticCellType.WIDGET.equals(metadata.getType())) { final Widget widget = metadata.getWidget(); final Element cellElement = cell.getElement(); @@ -1129,7 +1130,7 @@ public class Grid extends Composite implements int index = columnIndices.get(cell.getColumn()); StaticCell metadata = gridRow.getCell(index); - if (StaticCell.Type.WIDGET.equals(metadata.getType()) + if (GridStaticCellType.WIDGET.equals(metadata.getType()) && metadata.getWidget().isAttached()) { Widget widget = metadata.getWidget(); diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 56affc75d1..12952c7db8 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -30,11 +30,13 @@ import java.util.logging.Logger; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONValue; +import com.vaadin.client.ComponentConnector; +import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.data.DataSource.RowHandle; import com.vaadin.client.data.RpcDataSourceConnector.RpcDataSource; -import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.client.ui.AbstractHasComponentsConnector; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; import com.vaadin.client.ui.grid.GridStaticSection.StaticRow; @@ -73,7 +75,7 @@ import com.vaadin.shared.ui.grid.SortDirection; * @author Vaadin Ltd */ @Connect(com.vaadin.ui.components.grid.Grid.class) -public class GridConnector extends AbstractComponentConnector { +public class GridConnector extends AbstractHasComponentsConnector { /** * Custom implementation of the custom grid column using a JSONObject to @@ -297,8 +299,22 @@ public class GridConnector extends AbstractComponentConnector { int i = 0; for (CellState cellState : rowState.cells) { - StaticCell cell = row.getCell(diff + (i++)); - cell.setText(cellState.text); + StaticCell cell = row.getCell(i++); + switch (cellState.type) { + case TEXT: + cell.setText(cellState.text); + break; + case HTML: + cell.setHtml(cellState.text); + break; + case WIDGET: + ComponentConnector connector = (ComponentConnector) cellState.connector; + cell.setWidget(connector.getWidget()); + break; + default: + throw new IllegalStateException("unexpected cell type: " + + cellState.type); + } } for (List group : rowState.cellGroups) { @@ -570,4 +586,22 @@ public class GridConnector extends AbstractComponentConnector { + key.getClass().getSimpleName() + " (" + key + ")"; return (String) key; } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.client.HasComponentsConnector#updateCaption(com.vaadin.client + * .ComponentConnector) + */ + @Override + public void updateCaption(ComponentConnector connector) { + // TODO Auto-generated method stub + + } + + @Override + public void onConnectorHierarchyChange( + ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent) { + } } diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index 14e4d6de9c..1be0a92b8f 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -22,6 +22,7 @@ import java.util.HashSet; import java.util.List; import com.google.gwt.user.client.ui.Widget; +import com.vaadin.shared.ui.grid.GridStaticCellType; /** * Abstract base class for Grid header and footer sections. @@ -39,17 +40,13 @@ abstract class GridStaticSection> */ static class StaticCell { - public enum Type { - TEXT, HTML, WIDGET; - } - private Object content = null; private int colspan = 1; private GridStaticSection section; - private Type type = Type.TEXT; + private GridStaticCellType type = GridStaticCellType.TEXT; /** * Sets the text displayed in this cell. @@ -59,7 +56,7 @@ abstract class GridStaticSection> */ public void setText(String text) { this.content = text; - this.type = Type.TEXT; + this.type = GridStaticCellType.TEXT; section.requestSectionRefresh(); } @@ -69,7 +66,7 @@ abstract class GridStaticSection> * @return the plain text caption */ public String getText() { - if (type != Type.TEXT) { + if (type != GridStaticCellType.TEXT) { throw new IllegalStateException( "Cannot fetch Text from a cell with type " + type); } @@ -120,7 +117,7 @@ abstract class GridStaticSection> * @return the html content of the cell. */ public String getHtml() { - if (type != Type.HTML) { + if (type != GridStaticCellType.HTML) { throw new IllegalStateException( "Cannot fetch HTML from a cell with type " + type); } @@ -136,7 +133,7 @@ abstract class GridStaticSection> */ public void setHtml(String html) { this.content = html; - this.type = Type.HTML; + this.type = GridStaticCellType.HTML; section.requestSectionRefresh(); } @@ -149,7 +146,7 @@ abstract class GridStaticSection> * @return the widget in the cell */ public Widget getWidget() { - if (type != Type.WIDGET) { + if (type != GridStaticCellType.WIDGET) { throw new IllegalStateException( "Cannot fetch Widget from a cell with type " + type); } @@ -166,7 +163,7 @@ abstract class GridStaticSection> */ public void setWidget(Widget widget) { this.content = widget; - this.type = Type.WIDGET; + this.type = GridStaticCellType.WIDGET; section.requestSectionRefresh(); } @@ -175,7 +172,7 @@ abstract class GridStaticSection> * * @return the type of content the cell contains. */ - public Type getType() { + public GridStaticCellType getType() { return type; } } diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 2e0ac6bb31..d365d3e0cc 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -45,10 +45,16 @@ import com.vaadin.shared.ui.grid.GridColumnState; import com.vaadin.shared.ui.grid.GridServerRpc; import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.GridState.SharedSelectionMode; +import com.vaadin.shared.ui.grid.GridStaticCellType; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.shared.ui.grid.SortDirection; import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.Component; +import com.vaadin.ui.HasComponents; +import com.vaadin.ui.components.grid.GridFooter.FooterCell; +import com.vaadin.ui.components.grid.GridFooter.FooterRow; +import com.vaadin.ui.components.grid.GridHeader.HeaderCell; import com.vaadin.ui.components.grid.GridHeader.HeaderRow; import com.vaadin.ui.components.grid.selection.MultiSelectionModel; import com.vaadin.ui.components.grid.selection.NoSelectionModel; @@ -123,7 +129,8 @@ import com.vaadin.util.ReflectTools; * @since * @author Vaadin Ltd */ -public class Grid extends AbstractComponent implements SelectionChangeNotifier { +public class Grid extends AbstractComponent implements SelectionChangeNotifier, + HasComponents { /** * Selection modes representing built-in {@link SelectionModel @@ -1259,4 +1266,33 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { public GridFooter getFooter() { return footer; } + + @Override + public Iterator iterator() { + List componentList = new ArrayList(); + + GridHeader header = getHeader(); + for (int i = 0; i < header.getRowCount(); ++i) { + HeaderRow row = header.getRow(i); + for (Object propId : datasource.getContainerPropertyIds()) { + HeaderCell cell = row.getCell(propId); + if (cell.getCellState().type == GridStaticCellType.WIDGET) { + componentList.add(cell.getComponent()); + } + } + } + + GridFooter footer = getFooter(); + for (int i = 0; i < footer.getRowCount(); ++i) { + FooterRow row = footer.getRow(i); + for (Object propId : datasource.getContainerPropertyIds()) { + FooterCell cell = row.getCell(propId); + if (cell.getCellState().type == GridStaticCellType.WIDGET) { + componentList.add(cell.getComponent()); + } + } + } + + return componentList.iterator(); + } } diff --git a/server/src/com/vaadin/ui/components/grid/GridFooter.java b/server/src/com/vaadin/ui/components/grid/GridFooter.java index 84b2b70090..0a28a481cf 100644 --- a/server/src/com/vaadin/ui/components/grid/GridFooter.java +++ b/server/src/com/vaadin/ui/components/grid/GridFooter.java @@ -38,7 +38,7 @@ public class GridFooter extends GridStaticSection { } - public class FooterCell extends GridStaticSection.StaticCell { + public class FooterCell extends GridStaticSection.StaticCell { protected FooterCell(FooterRow row) { super(row); diff --git a/server/src/com/vaadin/ui/components/grid/GridHeader.java b/server/src/com/vaadin/ui/components/grid/GridHeader.java index 67f7bfdf69..9d7ec24a97 100644 --- a/server/src/com/vaadin/ui/components/grid/GridHeader.java +++ b/server/src/com/vaadin/ui/components/grid/GridHeader.java @@ -41,7 +41,7 @@ public class GridHeader extends GridStaticSection { } } - public class HeaderCell extends GridStaticSection.StaticCell { + public class HeaderCell extends GridStaticSection.StaticCell { protected HeaderCell(HeaderRow row) { super(row); diff --git a/server/src/com/vaadin/ui/components/grid/GridStaticSection.java b/server/src/com/vaadin/ui/components/grid/GridStaticSection.java index 8c983052ea..eb098d0d4e 100644 --- a/server/src/com/vaadin/ui/components/grid/GridStaticSection.java +++ b/server/src/com/vaadin/ui/components/grid/GridStaticSection.java @@ -26,9 +26,11 @@ import java.util.List; import java.util.Map; import com.vaadin.data.Container.Indexed; +import com.vaadin.shared.ui.grid.GridStaticCellType; import com.vaadin.shared.ui.grid.GridStaticSectionState; import com.vaadin.shared.ui.grid.GridStaticSectionState.CellState; import com.vaadin.shared.ui.grid.GridStaticSectionState.RowState; +import com.vaadin.ui.Component; /** * Abstract base class for Grid header and footer sections. @@ -47,7 +49,7 @@ abstract class GridStaticSection> * @param * the type of the cells in the row */ - abstract static class StaticRow> implements + abstract static class StaticRow implements Serializable { private RowState rowState = new RowState(); @@ -184,17 +186,13 @@ abstract class GridStaticSection> /** * A header or footer cell. Has a simple textual caption. - * - * @param - * the type of row this cells is in */ - abstract static class StaticCell> implements - Serializable { + abstract static class StaticCell implements Serializable { private CellState cellState = new CellState(); - private ROWTYPE row; + private StaticRow row; - protected StaticCell(ROWTYPE row) { + protected StaticCell(StaticRow row) { this.row = row; } @@ -203,7 +201,7 @@ abstract class GridStaticSection> * * @return row for this cell */ - public ROWTYPE getRow() { + public StaticRow getRow() { return row; } @@ -212,26 +210,83 @@ abstract class GridStaticSection> } /** - * Gets the current text content of this cell. Text is null if HTML or - * Component content is used. + * Sets the text displayed in this cell. * - * @return text content or null + * @param text + * a plain text caption + */ + public void setText(String text) { + cellState.text = text; + cellState.type = GridStaticCellType.TEXT; + row.section.markAsDirty(); + } + + /** + * Returns the text displayed in this cell. + * + * @return the plain text caption */ public String getText() { + if (cellState.type != GridStaticCellType.TEXT) { + throw new IllegalStateException( + "Cannot fetch Text from a cell with type " + + cellState.type); + } return cellState.text; } /** - * Sets the current text content of this cell. + * Returns the HTML content displayed in this cell. + * + * @return the html * - * @param text - * new text content */ - public void setText(String text) { - if (text != null && !text.equals(getCellState().text)) { - getCellState().text = text; - row.section.markAsDirty(); + public String getHtml() { + if (cellState.type != GridStaticCellType.HTML) { + throw new IllegalStateException( + "Cannot fetch HTML from a cell with type " + + cellState.type); } + return cellState.html; + } + + /** + * Sets the HTML content displayed in this cell. + * + * @param html + * the html to set + */ + public void setHtml(String html) { + cellState.html = html; + cellState.type = GridStaticCellType.HTML; + row.section.markAsDirty(); + } + + /** + * Returns the component displayed in this cell. + * + * @return the component + */ + public Component getComponent() { + if (cellState.type != GridStaticCellType.WIDGET) { + throw new IllegalStateException( + "Cannot fetch Component from a cell with type " + + cellState.type); + } + return (Component) cellState.connector; + } + + /** + * Sets the component displayed in this cell. + * + * @param component + * the component to set + */ + public void setComponent(Component component) { + component.setParent(row.section.grid); + cellState.connector = component; + cellState.type = GridStaticCellType.WIDGET; + row.section.markAsDirty(); } } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java b/shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java new file mode 100644 index 0000000000..eae4bc8da4 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +/** + * Enumeration, specifying the content type of a Cell in a GridStaticSection. + * + * @since + * @author Vaadin Ltd + */ +public enum GridStaticCellType { + /** + * Text content + */ + TEXT, + + /** + * HTML content + */ + HTML, + + /** + * Widget content + */ + WIDGET; +} \ No newline at end of file diff --git a/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java b/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java index 41f56199da..c3c373b5af 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java @@ -19,6 +19,8 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import com.vaadin.shared.Connector; + /** * Shared state for Grid headers and footers. * @@ -29,6 +31,12 @@ public class GridStaticSectionState implements Serializable { public static class CellState implements Serializable { public String text = ""; + + public String html = ""; + + public Connector connector = null; + + public GridStaticCellType type = GridStaticCellType.TEXT; } public static class RowState implements Serializable { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 8b3391253b..031ebf7fa5 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -28,14 +28,20 @@ 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; @@ -440,6 +446,88 @@ public class GridBasicFeatures extends AbstractComponentTest { } }, w, c); } + + LinkedHashMap defaultRows = new LinkedHashMap(); + 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() { + + @Override + public void execute(Grid grid, + GridStaticCellType value, Object columnIndex) { + final Object propertyId = (new ArrayList(grid + .getContainerDatasource() + .getContainerPropertyIds()) + .get((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(); + 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() { + + @Override + public void execute(Grid grid, + GridStaticCellType value, Object columnIndex) { + final Object propertyId = (new ArrayList(grid + .getContainerDatasource() + .getContainerPropertyIds()) + .get((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); } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java new file mode 100644 index 0000000000..fe32825d75 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java @@ -0,0 +1,56 @@ +/* + * 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 java.io.IOException; + +import org.junit.Test; + +import com.vaadin.testbench.elements.ButtonElement; + +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(); + + // Clicking also triggers sorting + assertEquals("2. Button clicked!", getLogRow(2)); + + compareScreen("button"); + } + + @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)); + } +} -- cgit v1.2.3 From e5230e6a2433f5c8a74c66b73e96d0454866d316 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 7 Aug 2014 15:47:54 +0300 Subject: Remove unnecessary compareScreen from GridStaticSectionComponentTest Change-Id: I60d30508ba9a57a704b11032d970121bfb640793 --- .../components/grid/basicfeatures/GridStaticSectionComponentTest.java | 2 -- 1 file changed, 2 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java index fe32825d75..d19d870548 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java @@ -36,8 +36,6 @@ public class GridStaticSectionComponentTest extends GridBasicFeaturesTest { // Clicking also triggers sorting assertEquals("2. Button clicked!", getLogRow(2)); - - compareScreen("button"); } @Test -- cgit v1.2.3 From 2ae0ff76032d5160c9bc9a7549a1c05c1434d800 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Wed, 6 Aug 2014 14:38:11 +0300 Subject: Ensure primary stylenames are correct #13334 Change-Id: If8c220d70a1537006a042be25b36bf880209268d --- client/src/com/vaadin/client/ui/grid/Grid.java | 6 ++ .../vaadin/tests/components/grid/GridElement.java | 81 ++++++++++++++ .../basicfeatures/GridBasicClientFeaturesTest.java | 8 -- .../grid/basicfeatures/GridBasicFeaturesTest.java | 3 +- .../grid/basicfeatures/GridStructureTest.java | 51 ++++----- .../grid/basicfeatures/GridStylingTest.java | 118 +++++++++++++++++++++ .../client/grid/GridBasicClientFeatures.java | 28 +++++ 7 files changed, 254 insertions(+), 41 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStylingTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index d5582e0202..395d510ec4 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -1217,6 +1217,12 @@ public class Grid extends Composite implements cellActiveStyleName = getStylePrimaryName() + "-cell-active"; headerFooterActiveStyleName = getStylePrimaryName() + "-header-active"; rowActiveStyleName = getStylePrimaryName() + "-row-active"; + + if (isAttached()) { + refreshHeader(); + refreshBody(); + refreshFooter(); + } } /** diff --git a/uitest/src/com/vaadin/tests/components/grid/GridElement.java b/uitest/src/com/vaadin/tests/components/grid/GridElement.java index 3b28c4eaa2..bd8cad45c6 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridElement.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridElement.java @@ -19,6 +19,7 @@ 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; @@ -185,6 +186,85 @@ public class GridElement extends AbstractComponentElement { 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 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 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 rootElements = findElements(By.xpath("./div")); + return rootElements.get(2); + } + /** * Helper function to get Grid subparts wrapped correctly * @@ -195,4 +275,5 @@ public class GridElement extends AbstractComponentElement { private TestBenchElement getSubPart(String subPartSelector) { return (TestBenchElement) findElement(By.vaadin(subPartSelector)); } + } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java index 559457ea1c..a8a2d4f12e 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java @@ -20,8 +20,6 @@ import org.openqa.selenium.Dimension; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; -import com.vaadin.testbench.TestBenchElement; -import com.vaadin.tests.components.grid.GridElement; import com.vaadin.tests.widgetset.server.grid.GridBasicClientFeatures; /** @@ -37,12 +35,6 @@ public abstract class GridBasicClientFeaturesTest extends GridBasicFeaturesTest return GridBasicClientFeatures.class; } - @Override - protected GridElement getGridElement() { - return ((TestBenchElement) findElement(By.className("v-grid"))) - .wrap(GridElement.class); - } - @Override protected void selectMenu(String menuCaption) { WebElement menuElement = getMenuElement(menuCaption); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java index 94d9766f78..6ef0ab5006 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java @@ -65,7 +65,8 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { } protected GridElement getGridElement() { - return $(GridElement.class).id("testComponent"); + return ((TestBenchElement) findElement(By.id("testComponent"))) + .wrap(GridElement.class); } protected void scrollGridVerticallyTo(double px) { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java index d52f512b4f..9adc4fa8a4 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java @@ -78,7 +78,7 @@ public class GridStructureTest extends GridBasicFeaturesTest { sleep(1000); // Check that row is loaded - assertThat(getBodyCellByRowAndColumn(11, 0).getText(), not("...")); + assertThat(getGridElement().getCell(11, 0).getText(), not("...")); } @Test @@ -88,10 +88,10 @@ public class GridStructureTest extends GridBasicFeaturesTest { // Freeze column 2 selectMenuPath("Component", "Columns", "Column 2", "Freeze"); - WebElement cell = getBodyCellByRowAndColumn(0, 0); + WebElement cell = getGridElement().getCell(0, 0); assertTrue(cell.getAttribute("class").contains("frozen")); - cell = getBodyCellByRowAndColumn(0, 1); + cell = getGridElement().getCell(0, 1); assertTrue(cell.getAttribute("class").contains("frozen")); } @@ -99,13 +99,13 @@ public class GridStructureTest extends GridBasicFeaturesTest { public void testInitialColumnWidths() throws Exception { openTestURL(); - WebElement cell = getBodyCellByRowAndColumn(0, 0); + WebElement cell = getGridElement().getCell(0, 0); assertEquals(100, cell.getSize().getWidth()); - cell = getBodyCellByRowAndColumn(0, 1); + cell = getGridElement().getCell(0, 1); assertEquals(150, cell.getSize().getWidth()); - cell = getBodyCellByRowAndColumn(0, 2); + cell = getGridElement().getCell(0, 2); assertEquals(200, cell.getSize().getWidth()); } @@ -114,27 +114,27 @@ public class GridStructureTest extends GridBasicFeaturesTest { openTestURL(); // Default column width is 100px - WebElement cell = getBodyCellByRowAndColumn(0, 0); + 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 = getBodyCellByRowAndColumn(0, 0); + 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 = getBodyCellByRowAndColumn(0, 1); + 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 = getBodyCellByRowAndColumn(0, 0); + cell = getGridElement().getCell(0, 0); assertEquals(100, cell.getSize().getWidth()); } @@ -184,17 +184,17 @@ public class GridStructureTest extends GridBasicFeaturesTest { openTestURL(); assertEquals("Unexpected cell initial state", "(0, 0)", - getBodyCellByRowAndColumn(0, 0).getText()); + getGridElement().getCell(0, 0).getText()); selectMenuPath("Component", "Body rows", "Modify first row (getItemProperty)"); assertEquals("(First) modification with getItemProperty failed", - "modified: 0", getBodyCellByRowAndColumn(0, 0).getText()); + "modified: 0", getGridElement().getCell(0, 0).getText()); selectMenuPath("Component", "Body rows", "Modify first row (getContainerProperty)"); assertEquals("(Second) modification with getItemProperty failed", - "modified: Column 0", getBodyCellByRowAndColumn(0, 0).getText()); + "modified: Column 0", getGridElement().getCell(0, 0).getText()); } @Test @@ -210,32 +210,19 @@ public class GridStructureTest extends GridBasicFeaturesTest { private void assertPrimaryStylename(String stylename) { assertTrue(getGridElement().getAttribute("class").contains(stylename)); - String tableWrapperStyleName = getTableWrapper().getAttribute("class"); + String tableWrapperStyleName = getGridElement().getTableWrapper() + .getAttribute("class"); assertTrue(tableWrapperStyleName.contains(stylename + "-tablewrapper")); - String hscrollStyleName = getHorizontalScroller().getAttribute("class"); + String hscrollStyleName = getGridElement().getHorizontalScroller() + .getAttribute("class"); assertTrue(hscrollStyleName.contains(stylename + "-scroller")); assertTrue(hscrollStyleName .contains(stylename + "-scroller-horizontal")); - String vscrollStyleName = getVerticalScroller().getAttribute("class"); + String vscrollStyleName = getGridElement().getVerticalScroller() + .getAttribute("class"); assertTrue(vscrollStyleName.contains(stylename + "-scroller")); assertTrue(vscrollStyleName.contains(stylename + "-scroller-vertical")); } - - private WebElement getBodyCellByRowAndColumn(int row, int column) { - return getGridElement().getCell(row, column); - } - - private WebElement getVerticalScroller() { - return getGridElement().findElement(By.xpath("./div[1]")); - } - - private WebElement getHorizontalScroller() { - return getGridElement().findElement(By.xpath("./div[2]")); - } - - private WebElement getTableWrapper() { - return getGridElement().findElement(By.xpath("./div[3]")); - } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStylingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStylingTest.java new file mode 100644 index 0000000000..e6c37ebf9d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStylingTest.java @@ -0,0 +1,118 @@ +/* + * 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.assertTrue; + +import org.junit.Test; + +import com.vaadin.testbench.By; + +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/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index 50f60f9847..6eac275a9a 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -130,6 +130,7 @@ public class GridBasicClientFeatures extends ds = new ListDataSource>(data); grid = getTestedWidget(); + grid.getElement().setId("testComponent"); grid.setDataSource(ds); grid.setSelectionMode(SelectionMode.NONE); @@ -240,6 +241,8 @@ public class GridBasicClientFeatures extends private void createStateMenu() { String[] selectionModePath = { "Component", "State", "Selection mode" }; + String[] primaryStyleNamePath = { "Component", "State", + "Primary Stylename" }; addMenuCommand("multi", new ScheduledCommand() { @Override @@ -261,6 +264,31 @@ public class GridBasicClientFeatures extends 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() { -- cgit v1.2.3 From e944e870b7d417450579c8ec5520e9d00890d515 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 7 Aug 2014 10:54:42 +0300 Subject: Separate GridBasicFeature tests into client and server subpackages Also move GridBasicClientFeatures to more reasonable place and rename the client side UI so it won't collide in jetty path search. Change-Id: I9475e2fd28a00ec83eeb03ebc122c12eb840ac0b --- .../basicfeatures/GridBasicClientFeatures.java | 41 ++ .../basicfeatures/GridBasicClientFeaturesTest.java | 2 - .../GridClientColumnPropertiesTest.java | 58 -- .../basicfeatures/GridClientSelectionTest.java | 35 -- .../grid/basicfeatures/GridFooterTest.java | 206 ------- .../grid/basicfeatures/GridHeaderTest.java | 358 ------------ .../basicfeatures/GridKeyboardNavigationTest.java | 170 ------ .../grid/basicfeatures/GridSelectionTest.java | 150 ----- .../grid/basicfeatures/GridSortingTest.java | 185 ------ .../GridStaticSectionComponentTest.java | 54 -- .../grid/basicfeatures/GridStaticSectionTest.java | 88 --- .../grid/basicfeatures/GridStructureTest.java | 228 -------- .../grid/basicfeatures/GridStylingTest.java | 118 ---- .../client/GridClientColumnPropertiesTest.java | 59 ++ .../client/GridClientSelectionTest.java | 37 ++ .../grid/basicfeatures/client/GridFooterTest.java | 207 +++++++ .../grid/basicfeatures/client/GridHeaderTest.java | 359 ++++++++++++ .../client/GridStaticSectionTest.java | 90 +++ .../grid/basicfeatures/client/GridStylingTest.java | 119 ++++ .../server/GridKeyboardNavigationTest.java | 172 ++++++ .../basicfeatures/server/GridSelectionTest.java | 151 +++++ .../grid/basicfeatures/server/GridSortingTest.java | 187 ++++++ .../server/GridStaticSectionComponentTest.java | 55 ++ .../basicfeatures/server/GridStructureTest.java | 229 ++++++++ .../client/grid/GridBasicClientFeatures.java | 632 --------------------- .../grid/GridBasicClientFeaturesConnector.java | 9 +- .../client/grid/GridBasicClientFeaturesWidget.java | 632 +++++++++++++++++++++ .../server/grid/GridBasicClientFeatures.java | 41 -- 28 files changed, 2343 insertions(+), 2329 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeatures.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientColumnPropertiesTest.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientSelectionTest.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStylingTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientColumnPropertiesTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridFooterTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridHeaderTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridStaticSectionTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridStylingTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridKeyboardNavigationTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java delete mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java delete mode 100644 uitest/src/com/vaadin/tests/widgetset/server/grid/GridBasicClientFeatures.java (limited to 'uitest/src') 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 index a8a2d4f12e..e3318fe650 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java @@ -20,8 +20,6 @@ import org.openqa.selenium.Dimension; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; -import com.vaadin.tests.widgetset.server.grid.GridBasicClientFeatures; - /** * Variant of GridBasicFeaturesTest to be used with GridBasicClientFeatures. * diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientColumnPropertiesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientColumnPropertiesTest.java deleted file mode 100644 index c9e048cc7f..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientColumnPropertiesTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -import com.vaadin.tests.widgetset.client.grid.GridBasicClientFeatures; - -public class GridClientColumnPropertiesTest extends GridBasicClientFeaturesTest { - - @Test - public void initialColumnWidths() { - openTestURL(); - - for (int col = 0; col < GridBasicClientFeatures.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); - } - -} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientSelectionTest.java deleted file mode 100644 index cb70c28b7d..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridClientSelectionTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -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/GridFooterTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java deleted file mode 100644 index d6a865ee29..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -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; - -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("Footer (0,2)", 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("HTML Footer", 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/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java deleted file mode 100644 index ccffee854a..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -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; - -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 cells = getGridHeaderRowCells(); - assertEquals(GridBasicFeatures.COLUMNS - 2, cells.size()); - - assertText("Header (0,0)", cells.get(0)); - assertHTML("Header (0,2)", cells.get(1)); - assertHTML("Header (0,4)", 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("Header (0,2)", cells.get(1)); - assertText("Header (0,3)", cells.get(2)); - assertHTML("Header (0,4)", 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("Header (0,2)", 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("HTML Header", 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/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java deleted file mode 100644 index e20b45bd1d..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridKeyboardNavigationTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -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; - -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()); - } -} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.java deleted file mode 100644 index 873c222f80..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSelectionTest.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import com.vaadin.testbench.TestBenchElement; -import com.vaadin.tests.components.grid.GridElement; -import com.vaadin.tests.components.grid.GridElement.GridRowElement; - -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()); - } - - 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/GridSortingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java deleted file mode 100644 index ee3f2a632b..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSortingTest.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -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; - -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"); - - 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]", getLogRow(2)); - assertEquals("4. Sort order: [Column 9 DESCENDING]", 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]", 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]", getLogRow(3)); - assertEquals("11. Sort order: [Column 7 DESCENDING]", 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 sortBy(String column) { - selectMenuPath("Component", "State", "Sort by column", column); - } -} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java deleted file mode 100644 index d19d870548..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -import static org.junit.Assert.assertEquals; - -import java.io.IOException; - -import org.junit.Test; - -import com.vaadin.testbench.elements.ButtonElement; - -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(); - - // Clicking also triggers sorting - assertEquals("2. Button clicked!", getLogRow(2)); - } - - @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/GridStaticSectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java deleted file mode 100644 index 5fac9cf860..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -import static org.junit.Assert.assertEquals; - -import com.vaadin.testbench.TestBenchElement; - -/** - * 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("Header (%d,%d)", headerId, i), - cell); - } else { - assertHTML(String.format( - "
Header (%d,%d)
", - 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("Footer (%d,%d)", footerId, i), - cell); - } else { - assertHTML(String.format( - "
Footer (%d,%d)
", - 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/GridStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java deleted file mode 100644 index 9adc4fa8a4..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStructureTest.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.IsNot.not; -import static org.junit.Assert.assertEquals; -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; - -public class GridStructureTest extends GridBasicFeaturesTest { - - @Test - public void testHidingColumn() throws Exception { - openTestURL(); - - // Column 0 should be visible - List 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 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()); - } - - 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/components/grid/basicfeatures/GridStylingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStylingTest.java deleted file mode 100644 index e6c37ebf9d..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStylingTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid.basicfeatures; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import com.vaadin.testbench.By; - -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/client/GridClientColumnPropertiesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientColumnPropertiesTest.java new file mode 100644 index 0000000000..ece9fdf7d7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientColumnPropertiesTest.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.basicfeatures.client; + +import static org.junit.Assert.assertEquals; + +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); + } + +} 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/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("Footer (0,2)", 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("HTML Footer", 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 cells = getGridHeaderRowCells(); + assertEquals(GridBasicFeatures.COLUMNS - 2, cells.size()); + + assertText("Header (0,0)", cells.get(0)); + assertHTML("Header (0,2)", cells.get(1)); + assertHTML("Header (0,4)", 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("Header (0,2)", cells.get(1)); + assertText("Header (0,3)", cells.get(2)); + assertHTML("Header (0,4)", 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("Header (0,2)", 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("HTML Header", 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("Header (%d,%d)", headerId, i), + cell); + } else { + assertHTML(String.format( + "
Header (%d,%d)
", + 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("Footer (%d,%d)", footerId, i), + cell); + } else { + assertHTML(String.format( + "
Footer (%d,%d)
", + 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/GridKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridKeyboardNavigationTest.java new file mode 100644 index 0000000000..948c753fec --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridKeyboardNavigationTest.java @@ -0,0 +1,172 @@ +/* + * 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.GridBasicFeaturesTest; +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()); + } +} 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..c190f7d0ec --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java @@ -0,0 +1,151 @@ +/* + * 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 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()); + } + + 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..a5a83c156e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java @@ -0,0 +1,187 @@ +/* + * 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"); + + 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]", getLogRow(2)); + assertEquals("4. Sort order: [Column 9 DESCENDING]", 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]", 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]", getLogRow(3)); + assertEquals("11. Sort order: [Column 7 DESCENDING]", 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 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..19a68a87f4 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java @@ -0,0 +1,55 @@ +/* + * 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(); + + // Clicking also triggers sorting + assertEquals("2. Button clicked!", getLogRow(2)); + } + + @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..7c5607d4e6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java @@ -0,0 +1,229 @@ +/* + * 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.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 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 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()); + } + + 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/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java deleted file mode 100644 index 6eac275a9a..0000000000 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ /dev/null @@ -1,632 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.widgetset.client.grid; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Random; - -import com.google.gwt.core.client.Scheduler.ScheduledCommand; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.HTML; -import com.vaadin.client.ui.grid.FlyweightCell; -import com.vaadin.client.ui.grid.Grid; -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.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.tests.widgetset.client.grid.GridBasicClientFeatures.Data; - -/** - * Grid basic client features test application. - * - * @since - * @author Vaadin Ltd - */ -public class GridBasicClientFeatures extends - PureGWTTestApplication>> { - - public static enum Renderers { - TEXT_RENDERER, HTML_RENDERER, NUMBER_RENDERER, DATE_RENDERER; - } - - private static final int MANUALLY_FORMATTED_COLUMNS = 5; - public static final int COLUMNS = 12; - public static final int ROWS = 1000; - - private final Grid> grid; - private final List> data; - private final ListDataSource> ds; - private final ListSorter> 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 createDataRow(int cols) { - List list = new ArrayList(cols); - for (int i = 0; i < cols; ++i) { - list.add(new Data()); - } - data.add(list); - return list; - } - - @SuppressWarnings("unchecked") - public GridBasicClientFeatures() { - super(new Grid>()); - - // Initialize data source - data = new ArrayList>(); - { - Random rand = new Random(); - rand.setSeed(13334); - long timestamp = 0; - for (int row = 0; row < ROWS; row++) { - - List 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 = "" + row + ""; - - d = datarow.get(col++); - d.value = Integer.valueOf(rand.nextInt()); - - d = datarow.get(col++); - d.value = Integer.valueOf(rand.nextInt(5)); - } - } - - ds = new ListDataSource>(data); - grid = getTestedWidget(); - grid.getElement().setId("testComponent"); - grid.setDataSource(ds); - grid.setSelectionMode(SelectionMode.NONE); - - sorter = new ListSorter>(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> column = new GridColumn>( - createRenderer(Renderers.TEXT_RENDERER)) { - @Override - public String getValue(List 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>( - createRenderer(Renderers.NUMBER_RENDERER)) { - @Override - public Integer getValue(List row) { - return (Integer) row.get(c).value; - } - }); - } - - // Some date - { - final int c = col++; - grid.addColumn(new GridColumn>( - createRenderer(Renderers.DATE_RENDERER)) { - @Override - public Date getValue(List row) { - return (Date) row.get(c).value; - } - }); - } - - // Row number as a HTML string - { - final int c = col++; - grid.addColumn(new GridColumn>( - createRenderer(Renderers.HTML_RENDERER)) { - @Override - public String getValue(List row) { - return (String) row.get(c).value; - } - }); - } - - // Random integer value - { - final int c = col++; - grid.addColumn(new GridColumn>( - createRenderer(Renderers.NUMBER_RENDERER)) { - @Override - public Integer getValue(List row) { - return (Integer) row.get(c).value; - } - }); - } - - // Random integer value between 0 and 5 - { - final int c = col++; - grid.addColumn(new GridColumn>( - createRenderer(Renderers.NUMBER_RENDERER)) { - @Override - public Integer getValue(List row) { - return (Integer) row.get(c).value; - } - }); - } - - setHeaderTexts(grid.getHeader().getRow(0)); - - // - // Populate the menu - // - - createStateMenu(); - createColumnsMenu(); - createHeaderMenu(); - createFooterMenu(); - - grid.getElement().getStyle().setZIndex(0); - add(grid); - } - - 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; - addMenuCommand("Visible", new ScheduledCommand() { - @Override - public void execute() { - grid.getColumn(index).setVisible( - !grid.getColumn(index).isVisible()); - } - }, "Component", "Columns", "Column " + i); - addMenuCommand("Sortable", new ScheduledCommand() { - @Override - public void execute() { - grid.getColumn(index).setSortable( - !grid.getColumn(index).isSortable()); - } - }, "Component", "Columns", "Column " + i); - - addMenuCommand("auto", new ScheduledCommand() { - @Override - public void execute() { - grid.getColumn(index).setWidth(-1); - } - }, "Component", "Columns", "Column " + i, "Width"); - addMenuCommand("50px", new ScheduledCommand() { - @Override - public void execute() { - grid.getColumn(index).setWidth(50); - } - }, "Component", "Columns", "Column " + i, "Width"); - addMenuCommand("200px", new ScheduledCommand() { - @Override - public void execute() { - grid.getColumn(index).setWidth(200); - } - }, "Component", "Columns", "Column " + i, "Width"); - - // Header types - addMenuCommand("Text Header", new ScheduledCommand() { - @Override - public void execute() { - grid.getHeader().getRow(0).getCell(index) - .setText("Text Header"); - } - }, "Component", "Columns", "Column " + i, "Header Type"); - addMenuCommand("HTML Header", new ScheduledCommand() { - @Override - public void execute() { - grid.getHeader().getRow(0).getCell(index) - .setHtml("HTML Header"); - } - }, "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(index).setWidget(button); - } - }, "Component", "Columns", "Column " + i, "Header Type"); - - // Footer types - addMenuCommand("Text Footer", new ScheduledCommand() { - @Override - public void execute() { - grid.getFooter().getRow(0).getCell(index) - .setText("Text Footer"); - } - }, "Component", "Columns", "Column " + i, "Footer Type"); - addMenuCommand("HTML Footer", new ScheduledCommand() { - @Override - public void execute() { - grid.getFooter().getRow(0).getCell(index) - .setHtml("HTML Footer"); - } - }, "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(index).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(i).setText(caption); - } else if (i % 2 == 0) { - row.getCell(i).setHtml("" + caption + ""); - } else { - row.getCell(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(i).setText(caption); - } else if (i % 2 == 0) { - row.getCell(i).setHtml("" + caption + ""); - } else { - row.getCell(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(0), row.getCell(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 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(0), row.getCell(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 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, "" + htmlString + ""); - } - }; - - case NUMBER_RENDERER: - return new NumberRenderer(); - - case DATE_RENDERER: - return new DateRenderer(); - - default: - return new TextRenderer(); - } - } -} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesConnector.java index 4b640e84e5..b0841b69fb 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesConnector.java @@ -17,20 +17,21 @@ 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(com.vaadin.tests.widgetset.server.grid.GridBasicClientFeatures.GridTestComponent.class) +@Connect(GridTestComponent.class) public class GridBasicClientFeaturesConnector extends AbstractComponentConnector { @Override - public GridBasicClientFeatures getWidget() { - return (GridBasicClientFeatures) super.getWidget(); + 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..8a5a75da38 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -0,0 +1,632 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.client.grid; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Random; + +import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.HTML; +import com.vaadin.client.ui.grid.FlyweightCell; +import com.vaadin.client.ui.grid.Grid; +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.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.tests.widgetset.client.grid.GridBasicClientFeaturesWidget.Data; + +/** + * Grid basic client features test application. + * + * @since + * @author Vaadin Ltd + */ +public class GridBasicClientFeaturesWidget extends + PureGWTTestApplication>> { + + public static enum Renderers { + TEXT_RENDERER, HTML_RENDERER, NUMBER_RENDERER, DATE_RENDERER; + } + + private static final int MANUALLY_FORMATTED_COLUMNS = 5; + public static final int COLUMNS = 12; + public static final int ROWS = 1000; + + private final Grid> grid; + private final List> data; + private final ListDataSource> ds; + private final ListSorter> 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 createDataRow(int cols) { + List list = new ArrayList(cols); + for (int i = 0; i < cols; ++i) { + list.add(new Data()); + } + data.add(list); + return list; + } + + @SuppressWarnings("unchecked") + public GridBasicClientFeaturesWidget() { + super(new Grid>()); + + // Initialize data source + data = new ArrayList>(); + { + Random rand = new Random(); + rand.setSeed(13334); + long timestamp = 0; + for (int row = 0; row < ROWS; row++) { + + List 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 = "" + row + ""; + + d = datarow.get(col++); + d.value = Integer.valueOf(rand.nextInt()); + + d = datarow.get(col++); + d.value = Integer.valueOf(rand.nextInt(5)); + } + } + + ds = new ListDataSource>(data); + grid = getTestedWidget(); + grid.getElement().setId("testComponent"); + grid.setDataSource(ds); + grid.setSelectionMode(SelectionMode.NONE); + + sorter = new ListSorter>(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> column = new GridColumn>( + createRenderer(Renderers.TEXT_RENDERER)) { + @Override + public String getValue(List 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>( + createRenderer(Renderers.NUMBER_RENDERER)) { + @Override + public Integer getValue(List row) { + return (Integer) row.get(c).value; + } + }); + } + + // Some date + { + final int c = col++; + grid.addColumn(new GridColumn>( + createRenderer(Renderers.DATE_RENDERER)) { + @Override + public Date getValue(List row) { + return (Date) row.get(c).value; + } + }); + } + + // Row number as a HTML string + { + final int c = col++; + grid.addColumn(new GridColumn>( + createRenderer(Renderers.HTML_RENDERER)) { + @Override + public String getValue(List row) { + return (String) row.get(c).value; + } + }); + } + + // Random integer value + { + final int c = col++; + grid.addColumn(new GridColumn>( + createRenderer(Renderers.NUMBER_RENDERER)) { + @Override + public Integer getValue(List row) { + return (Integer) row.get(c).value; + } + }); + } + + // Random integer value between 0 and 5 + { + final int c = col++; + grid.addColumn(new GridColumn>( + createRenderer(Renderers.NUMBER_RENDERER)) { + @Override + public Integer getValue(List row) { + return (Integer) row.get(c).value; + } + }); + } + + setHeaderTexts(grid.getHeader().getRow(0)); + + // + // Populate the menu + // + + createStateMenu(); + createColumnsMenu(); + createHeaderMenu(); + createFooterMenu(); + + grid.getElement().getStyle().setZIndex(0); + add(grid); + } + + 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; + addMenuCommand("Visible", new ScheduledCommand() { + @Override + public void execute() { + grid.getColumn(index).setVisible( + !grid.getColumn(index).isVisible()); + } + }, "Component", "Columns", "Column " + i); + addMenuCommand("Sortable", new ScheduledCommand() { + @Override + public void execute() { + grid.getColumn(index).setSortable( + !grid.getColumn(index).isSortable()); + } + }, "Component", "Columns", "Column " + i); + + addMenuCommand("auto", new ScheduledCommand() { + @Override + public void execute() { + grid.getColumn(index).setWidth(-1); + } + }, "Component", "Columns", "Column " + i, "Width"); + addMenuCommand("50px", new ScheduledCommand() { + @Override + public void execute() { + grid.getColumn(index).setWidth(50); + } + }, "Component", "Columns", "Column " + i, "Width"); + addMenuCommand("200px", new ScheduledCommand() { + @Override + public void execute() { + grid.getColumn(index).setWidth(200); + } + }, "Component", "Columns", "Column " + i, "Width"); + + // Header types + addMenuCommand("Text Header", new ScheduledCommand() { + @Override + public void execute() { + grid.getHeader().getRow(0).getCell(index) + .setText("Text Header"); + } + }, "Component", "Columns", "Column " + i, "Header Type"); + addMenuCommand("HTML Header", new ScheduledCommand() { + @Override + public void execute() { + grid.getHeader().getRow(0).getCell(index) + .setHtml("HTML Header"); + } + }, "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(index).setWidget(button); + } + }, "Component", "Columns", "Column " + i, "Header Type"); + + // Footer types + addMenuCommand("Text Footer", new ScheduledCommand() { + @Override + public void execute() { + grid.getFooter().getRow(0).getCell(index) + .setText("Text Footer"); + } + }, "Component", "Columns", "Column " + i, "Footer Type"); + addMenuCommand("HTML Footer", new ScheduledCommand() { + @Override + public void execute() { + grid.getFooter().getRow(0).getCell(index) + .setHtml("HTML Footer"); + } + }, "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(index).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(i).setText(caption); + } else if (i % 2 == 0) { + row.getCell(i).setHtml("" + caption + ""); + } else { + row.getCell(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(i).setText(caption); + } else if (i % 2 == 0) { + row.getCell(i).setHtml("" + caption + ""); + } else { + row.getCell(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(0), row.getCell(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 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(0), row.getCell(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 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, "" + htmlString + ""); + } + }; + + case NUMBER_RENDERER: + return new NumberRenderer(); + + case DATE_RENDERER: + return new DateRenderer(); + + default: + return new TextRenderer(); + } + } +} diff --git a/uitest/src/com/vaadin/tests/widgetset/server/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/server/grid/GridBasicClientFeatures.java deleted file mode 100644 index fb217dc232..0000000000 --- a/uitest/src/com/vaadin/tests/widgetset/server/grid/GridBasicClientFeatures.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.widgetset.server.grid; - -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()); - } - -} -- cgit v1.2.3 From 36b8edd18b8b0096d00e572783c04a1fa827063f Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 19 Aug 2014 11:20:04 +0300 Subject: Add DataAvailableEvent and handler for it (#13334) Change-Id: I340b870f6313ec8f8d3b06ff97995d8242e66bfd --- .../client/data/AbstractRemoteDataSource.java | 2 + .../com/vaadin/client/data/DataChangeHandler.java | 11 +++++ client/src/com/vaadin/client/data/DataSource.java | 3 ++ .../vaadin/client/ui/grid/DataAvailableEvent.java | 55 ++++++++++++++++++++++ .../client/ui/grid/DataAvailableHandler.java | 37 +++++++++++++++ client/src/com/vaadin/client/ui/grid/Grid.java | 39 +++++++++++++++ .../client/ui/grid/datasources/ListDataSource.java | 25 +++++----- .../grid/GridClientColumnRendererConnector.java | 2 + 8 files changed, 163 insertions(+), 11 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/DataAvailableEvent.java create mode 100644 client/src/com/vaadin/client/ui/grid/DataAvailableHandler.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java index d7d590dc42..ca2d2bc83e 100644 --- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java +++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java @@ -274,6 +274,7 @@ public abstract class AbstractRemoteDataSource implements DataSource { if (dataChangeHandler != null && !cached.isEmpty()) { // Push currently cached data to the implementation dataChangeHandler.dataUpdated(cached.getStart(), cached.length()); + dataChangeHandler.dataAvailable(cached.getStart(), cached.length()); } } @@ -332,6 +333,7 @@ public abstract class AbstractRemoteDataSource implements DataSource { cached = newUsefulData; } } + dataChangeHandler.dataAvailable(cached.getStart(), cached.length()); updatePinnedRows(rowData); } diff --git a/client/src/com/vaadin/client/data/DataChangeHandler.java b/client/src/com/vaadin/client/data/DataChangeHandler.java index 9553ef53c1..fe72fe673a 100644 --- a/client/src/com/vaadin/client/data/DataChangeHandler.java +++ b/client/src/com/vaadin/client/data/DataChangeHandler.java @@ -56,4 +56,15 @@ public interface DataChangeHandler { * the number of added rows */ public void dataAdded(int firstRowIndex, int numberOfRows); + + /** + * Called when rows requested with + * {@link DataSource#ensureAvailability(int, int)} rows are available. + * + * @param firstRowIndex + * the index of the first available row + * @param numberOfRows + * the number of available rows + */ + public void dataAvailable(int firstRowIndex, int numberOfRows); } diff --git a/client/src/com/vaadin/client/data/DataSource.java b/client/src/com/vaadin/client/data/DataSource.java index 33f60eadcc..24cef548c5 100644 --- a/client/src/com/vaadin/client/data/DataSource.java +++ b/client/src/com/vaadin/client/data/DataSource.java @@ -133,6 +133,9 @@ public interface DataSource { * This method triggers lazy loading of data if necessary. The change * handler registered using {@link #setDataChangeHandler(DataChangeHandler)} * is informed when new data has been loaded. + *

+ * After any possible lazy loading and updates are done, the change handler + * is informed that new data is available. * * @param firstRowIndex * the index of the first needed row diff --git a/client/src/com/vaadin/client/ui/grid/DataAvailableEvent.java b/client/src/com/vaadin/client/ui/grid/DataAvailableEvent.java new file mode 100644 index 0000000000..62b188c0ea --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/DataAvailableEvent.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid; + +import com.google.gwt.event.shared.GwtEvent; +import com.vaadin.shared.ui.grid.Range; + +/** + * Event object describing a change of row availability in DataSource of a Grid. + * + * @since + * @author Vaadin Ltd + */ +public class DataAvailableEvent extends GwtEvent { + + private Range rowsAvailable; + public static final Type TYPE = new Type(); + + public DataAvailableEvent(Range rowsAvailable) { + this.rowsAvailable = rowsAvailable; + } + + /** + * Returns the range of available rows in {@link DataSource} for this event. + * + * @return range of available rows + */ + public Range getAvailableRows() { + return rowsAvailable; + } + + @Override + public Type getAssociatedType() { + return TYPE; + } + + @Override + protected void dispatch(DataAvailableHandler handler) { + handler.onDataAvailable(this); + } + +} diff --git a/client/src/com/vaadin/client/ui/grid/DataAvailableHandler.java b/client/src/com/vaadin/client/ui/grid/DataAvailableHandler.java new file mode 100644 index 0000000000..06ea08a17e --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/DataAvailableHandler.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.client.ui.grid; + +import com.google.gwt.event.shared.EventHandler; + +/** + * Handler for {@link DataAvailableEvent}s. + * + * @since + * @author Vaadin Ltd + */ +public interface DataAvailableHandler extends EventHandler { + + /** + * Called when DataSource has data available. Supplied with row range. + * + * @param availableRows + * Range of rows available in the DataSource + * @return true if the command was successfully completed, false to call + * again the next time new data is available + */ + public void onDataAvailable(DataAvailableEvent event); +} diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index a407038917..531e27098c 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -25,6 +25,8 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.Element; @@ -561,6 +563,11 @@ public class Grid extends Composite implements */ private DataSource dataSource; + /** + * Currently available row range in DataSource. + */ + private Range currentDataAvailable = Range.withLength(0, 0); + /** * The last column frozen counter from the left */ @@ -1569,6 +1576,13 @@ public class Grid extends Composite implements public void dataAdded(int firstIndex, int numberOfItems) { escalator.getBody().insertRows(firstIndex, numberOfItems); } + + @Override + public void dataAvailable(int firstIndex, int numberOfItems) { + currentDataAvailable = Range.withLength(firstIndex, + numberOfItems); + fireEvent(new DataAvailableEvent(currentDataAvailable)); + } }); int previousRowCount = escalator.getBody().getRowCount(); @@ -2317,6 +2331,31 @@ public class Grid extends Composite implements return addHandler(handler, SortEvent.getType()); } + /** + * Register a GWT event handler for a data available event. This handler + * gets called whenever the {@link DataSource} for this Grid has new data + * available. + *

+ * This handle will be fired with the current available data after + * registration is done. + * + * @param handler + * a data available event handler + * @return the registartion for the event + */ + public HandlerRegistration addDataAvailableHandler( + final DataAvailableHandler handler) { + // Deferred call to handler with current row range + Scheduler.get().scheduleFinally(new ScheduledCommand() { + @Override + public void execute() { + handler.onDataAvailable(new DataAvailableEvent( + currentDataAvailable)); + } + }); + return addHandler(handler, DataAvailableEvent.TYPE); + } + /** * Apply sorting to data source. */ diff --git a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java index fc76955410..ef021a496a 100644 --- a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java +++ b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java @@ -32,23 +32,23 @@ import com.vaadin.shared.util.SharedUtil; * A simple list based on an in-memory data source for simply adding a list of * row pojos to the grid. Based on a wrapped list instance which supports adding * and removing of items. - * + * *

* Usage: - * + * *

  * ListDataSource<Integer> ds = new ListDataSource<Integer>(1, 2, 3, 4);
- *
+ * 
  * // Add item to the data source
  * ds.asList().add(5);
- *
+ * 
  * // Remove item from the data source
  * ds.asList().remove(3);
- *
+ * 
  * // Add multiple items
  * ds.asList().addAll(Arrays.asList(5, 6, 7));
  * 
- * + * * @since * @author Vaadin Ltd */ @@ -202,6 +202,7 @@ public class ListDataSource implements DataSource { // Have to update the whole list as the removal does not // have to be a continuous range changeHandler.dataUpdated(0, ds.size()); + changeHandler.dataAvailable(0, ds.size()); } return true; } @@ -215,6 +216,7 @@ public class ListDataSource implements DataSource { // Have to update the whole list as the retain does not // have to be a continuous range changeHandler.dataUpdated(0, ds.size()); + changeHandler.dataAvailable(0, ds.size()); } return true; } @@ -344,8 +346,8 @@ public class ListDataSource implements DataSource { * data source after the data source has been constructed. To add or remove * items to the data source after it has been constructed use * {@link ListDataSource#asList()}. - * - * + * + * * @param datasource * The list to use for providing the data to the grid */ @@ -361,7 +363,7 @@ public class ListDataSource implements DataSource { * Constructs a data source with a set of rows. You can dynamically add and * remove rows from the data source via the list you get from * {@link ListDataSource#asList()} - * + * * @param rows * The rows to initially add to the data source */ @@ -380,6 +382,7 @@ public class ListDataSource implements DataSource { throw new IllegalStateException( "Trying to fetch rows outside of array"); } + changeHandler.dataAvailable(firstRowIndex, numberOfRows); } @Override @@ -403,7 +406,7 @@ public class ListDataSource implements DataSource { *

* Note: The list is not the same list as passed into the data source via * the constructor. - * + * * @return Returns a list implementation that wraps the real list that backs * the data source and provides events for the data source * listeners. @@ -421,7 +424,7 @@ public class ListDataSource implements DataSource { /** * Sort entire container according to a {@link Comparator}. - * + * * @param comparator * a comparator object, which compares two data source entries * (beans/pojos) diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index c0e57e97aa..7a9f8a06f5 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -84,6 +84,8 @@ public class GridClientColumnRendererConnector extends DelayedDataSource.this.firstRowIndex = firstRowIndex; DelayedDataSource.this.numberOfRows = numberOfRows; dataChangeHandler.dataUpdated(firstRowIndex, numberOfRows); + dataChangeHandler + .dataAvailable(firstRowIndex, numberOfRows); } }.schedule(latency); } -- cgit v1.2.3 From c532e42ec703079eb024ca8e1f03442d493a40e7 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 13 Aug 2014 16:39:40 +0300 Subject: Implement KeyEvents for Grid (#13334) Change-Id: Ida7a358aa23a4c96232a01bed0b4810fb91dd832 --- .../com/vaadin/client/ui/grid/FlyweightCell.java | 3 +- client/src/com/vaadin/client/ui/grid/Grid.java | 154 ++++++++++++++++++++- client/src/com/vaadin/client/ui/grid/Row.java | 4 +- .../keyevents/AbstractGridKeyEventHandler.java | 43 ++++++ .../ui/grid/keyevents/BodyKeyDownHandler.java | 28 ++++ .../ui/grid/keyevents/BodyKeyPressHandler.java | 28 ++++ .../client/ui/grid/keyevents/BodyKeyUpHandler.java | 28 ++++ .../ui/grid/keyevents/FooterKeyDownHandler.java | 28 ++++ .../ui/grid/keyevents/FooterKeyPressHandler.java | 28 ++++ .../ui/grid/keyevents/FooterKeyUpHandler.java | 28 ++++ .../client/ui/grid/keyevents/GridKeyDownEvent.java | 51 +++++++ .../ui/grid/keyevents/GridKeyPressEvent.java | 51 +++++++ .../client/ui/grid/keyevents/GridKeyUpEvent.java | 51 +++++++ .../ui/grid/keyevents/HeaderKeyDownHandler.java | 28 ++++ .../ui/grid/keyevents/HeaderKeyPressHandler.java | 28 ++++ .../ui/grid/keyevents/HeaderKeyUpHandler.java | 28 ++++ .../client/GridClientKeyEventsTest.java | 108 +++++++++++++++ .../client/grid/GridBasicClientFeaturesWidget.java | 127 ++++++++++++++++- 18 files changed, 834 insertions(+), 10 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientKeyEventsTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java index dcc543de9c..30cc4fc79e 100644 --- a/client/src/com/vaadin/client/ui/grid/FlyweightCell.java +++ b/client/src/com/vaadin/client/ui/grid/FlyweightCell.java @@ -17,7 +17,6 @@ package com.vaadin.client.ui.grid; import java.util.List; -import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.TableCellElement; @@ -70,7 +69,7 @@ public class FlyweightCell { * Returns the element of the cell. Can be either a TD element * or a TH element. */ - public Element getElement() { + public TableCellElement getElement() { assertSetup(); return element; } diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 531e27098c..a2bb0d3f09 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -33,7 +33,9 @@ import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.EventTarget; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.TableCellElement; +import com.google.gwt.dom.client.TableRowElement; import com.google.gwt.dom.client.Touch; +import com.google.gwt.event.dom.client.KeyCodeEvent; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.touch.client.Point; @@ -50,6 +52,22 @@ import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.grid.GridFooter.FooterRow; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler; +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDownHandler; +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPressHandler; +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUpHandler; +import com.vaadin.client.ui.grid.keyevents.BodyKeyDownHandler; +import com.vaadin.client.ui.grid.keyevents.BodyKeyPressHandler; +import com.vaadin.client.ui.grid.keyevents.BodyKeyUpHandler; +import com.vaadin.client.ui.grid.keyevents.FooterKeyDownHandler; +import com.vaadin.client.ui.grid.keyevents.FooterKeyPressHandler; +import com.vaadin.client.ui.grid.keyevents.FooterKeyUpHandler; +import com.vaadin.client.ui.grid.keyevents.GridKeyDownEvent; +import com.vaadin.client.ui.grid.keyevents.GridKeyPressEvent; +import com.vaadin.client.ui.grid.keyevents.GridKeyUpEvent; +import com.vaadin.client.ui.grid.keyevents.HeaderKeyDownHandler; +import com.vaadin.client.ui.grid.keyevents.HeaderKeyPressHandler; +import com.vaadin.client.ui.grid.keyevents.HeaderKeyUpHandler; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.WidgetRenderer; import com.vaadin.client.ui.grid.selection.HasSelectionChangeHandlers; @@ -105,6 +123,68 @@ import com.vaadin.shared.ui.grid.SortDirection; public class Grid extends Composite implements HasSelectionChangeHandlers, SubPartAware { + public static abstract class AbstractGridKeyEvent + extends KeyCodeEvent { + + /** + * Enum describing different section of Grid. + */ + public enum GridSection { + HEADER, BODY, FOOTER + } + + private Grid grid; + protected Cell activeCell; + protected GridSection activeSection; + private final Type associatedType = new Type( + getBrowserEventType(), this); + + public AbstractGridKeyEvent(Grid grid) { + this.grid = grid; + } + + protected abstract String getBrowserEventType(); + + /** + * Gets the Grid instance for this event. + * + * @return grid + */ + public Grid getGrid() { + return grid; + } + + /** + * Gets the active cell for this event. + * + * @return active cell + */ + public Cell getActiveCell() { + return activeCell; + } + + @Override + protected void dispatch(HANDLER handler) { + activeCell = grid.activeCellHandler.getActiveCell(); + activeSection = GridSection.FOOTER; + final RowContainer container = grid.activeCellHandler.container; + if (container == grid.escalator.getHeader()) { + activeSection = GridSection.HEADER; + } else if (container == grid.escalator.getBody()) { + activeSection = GridSection.BODY; + } + } + + @Override + public Type getAssociatedType() { + return associatedType; + } + } + + private GridKeyDownEvent keyDown = new GridKeyDownEvent(this); + private GridKeyUpEvent keyUp = new GridKeyUpEvent(this); + private GridKeyPressEvent keyPress = new GridKeyPressEvent(this); + private class ActiveCellHandler { private RowContainer container = escalator.getBody(); @@ -113,13 +193,17 @@ public class Grid extends Composite implements private int lastActiveBodyRow = 0; private int lastActiveHeaderRow = 0; private int lastActiveFooterRow = 0; - private Element cellWithActiveStyle = null; - private Element rowWithActiveStyle = null; + private TableCellElement cellWithActiveStyle = null; + private TableRowElement rowWithActiveStyle = null; public ActiveCellHandler() { sinkEvents(getNavigationEvents()); } + private Cell getActiveCell() { + return new Cell(activeRow, activeColumn, cellWithActiveStyle); + } + /** * Sets style names for given cell when needed. */ @@ -594,7 +678,7 @@ public class Grid extends Composite implements */ private SelectionModel selectionModel; - private final ActiveCellHandler activeCellHandler; + protected final ActiveCellHandler activeCellHandler; private final LazySorter lazySorter = new LazySorter(); @@ -1199,8 +1283,10 @@ public class Grid extends Composite implements } }); - // Sink header events + // Sink header events and key events sinkEvents(getHeader().getConsumedEvents()); + sinkEvents(Arrays.asList(BrowserEvents.KEYDOWN, BrowserEvents.KEYUP, + BrowserEvents.KEYPRESS)); } @Override @@ -2356,6 +2442,66 @@ public class Grid extends Composite implements return addHandler(handler, DataAvailableEvent.TYPE); } + /** + * Register a KeyDown handler to this Grid. If the handler is a + * HeaderKeyDownHandler, it will be fired only when a header cell is active. + * The same goes for body and footer with their respective handlers. + * + * @param handler + * the key handler to register + * @return the registration for the event + */ + public > HandlerRegistration addKeyDownHandler( + HANDLER handler) { + if (handler instanceof BodyKeyDownHandler + || handler instanceof HeaderKeyDownHandler + || handler instanceof FooterKeyDownHandler) { + return addHandler(handler, keyDown.getAssociatedType()); + } + throw new IllegalArgumentException( + "Handler not a valid extension of GridKeyDownHandler"); + } + + /** + * Register a KeyUp handler to this Grid. If the handler is a + * HeaderKeyUpHandler, it will be fired only when a header cell is active. + * The same goes for body and footer with their respective handlers. + * + * @param handler + * the key handler to register + * @return the registration for the event + */ + public > HandlerRegistration addKeyUpHandler( + HANDLER handler) { + if (handler instanceof BodyKeyUpHandler + || handler instanceof HeaderKeyUpHandler + || handler instanceof FooterKeyUpHandler) { + return addHandler(handler, keyUp.getAssociatedType()); + } + throw new IllegalArgumentException( + "Handler not a valid extension of GridKeyUpHandler"); + } + + /** + * Register a KeyPress handler to this Grid. If the handler is a + * HeaderKeyPressHandler, it will be fired only when a header cell is + * active. The same goes for body and footer with their respective handlers. + * + * @param handler + * the key handler to register + * @return the registration for the event + */ + public > HandlerRegistration addKeyPressHandler( + HANDLER handler) { + if (handler instanceof BodyKeyPressHandler + || handler instanceof HeaderKeyPressHandler + || handler instanceof FooterKeyPressHandler) { + return addHandler(handler, keyPress.getAssociatedType()); + } + throw new IllegalArgumentException( + "Handler not a valid extension of GridKeyPressHandler"); + } + /** * Apply sorting to data source. */ diff --git a/client/src/com/vaadin/client/ui/grid/Row.java b/client/src/com/vaadin/client/ui/grid/Row.java index a5317e52c4..6419a98574 100644 --- a/client/src/com/vaadin/client/ui/grid/Row.java +++ b/client/src/com/vaadin/client/ui/grid/Row.java @@ -16,7 +16,7 @@ package com.vaadin.client.ui.grid; -import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.TableRowElement; /** * A representation of a row in an {@link Escalator}. @@ -44,5 +44,5 @@ public interface Row { * * @return the root element of the row */ - public Element getElement(); + public TableRowElement getElement(); } \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java new file mode 100644 index 0000000000..28a85924fa --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.google.gwt.event.shared.EventHandler; + +/** + * Base interface of all handlers for {@link AbstractGridKeyEvent}s. + * + * @since + * @author Vaadin Ltd + */ +public abstract interface AbstractGridKeyEventHandler extends EventHandler { + + public abstract interface GridKeyDownHandler extends + AbstractGridKeyEventHandler { + public void onKeyDown(GridKeyDownEvent event); + } + + public abstract interface GridKeyUpHandler extends + AbstractGridKeyEventHandler { + public void onKeyUp(GridKeyUpEvent event); + } + + public abstract interface GridKeyPressHandler extends + AbstractGridKeyEventHandler { + public void onKeyPress(GridKeyPressEvent event); + } + +} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java new file mode 100644 index 0000000000..a3b76ea5d7 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDownHandler; + +/** + * Handler for {@link GridKeyDownEvent}s that happen when active cell is in the + * body of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface BodyKeyDownHandler extends GridKeyDownHandler { +} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java new file mode 100644 index 0000000000..5548994cf9 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPressHandler; + +/** + * Handler for {@link GridKeyPressEvent}s that happen when active cell is in the + * body of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface BodyKeyPressHandler extends GridKeyPressHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java new file mode 100644 index 0000000000..33b4fc81fe --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUpHandler; + +/** + * Handler for {@link GridKeyUpEvent}s that happen when active cell is in the + * body of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface BodyKeyUpHandler extends GridKeyUpHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java new file mode 100644 index 0000000000..e90f52e736 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDownHandler; + +/** + * Handler for {@link GridKeyDownEvent}s that happen when active cell is in the + * footer of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface FooterKeyDownHandler extends GridKeyDownHandler { +} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java new file mode 100644 index 0000000000..58f48f36f5 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPressHandler; + +/** + * Handler for {@link GridKeyPressEvent}s that happen when active cell is in the + * footer of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface FooterKeyPressHandler extends GridKeyPressHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java new file mode 100644 index 0000000000..d6bcddf710 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUpHandler; + +/** + * Handler for {@link GridKeyUpEvent}s that happen when active cell is in the + * footer of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface FooterKeyUpHandler extends GridKeyUpHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java new file mode 100644 index 0000000000..8af65dbf49 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.google.gwt.dom.client.BrowserEvents; +import com.vaadin.client.ui.grid.Grid; +import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDownHandler; + +/** + * Represents native key down event in Grid. + * + * @since + * @author Vaadin Ltd + */ +public class GridKeyDownEvent extends + AbstractGridKeyEvent> { + + public GridKeyDownEvent(Grid grid) { + super(grid); + } + + @Override + protected void dispatch(GridKeyDownHandler handler) { + super.dispatch(handler); + if ((activeSection == GridSection.BODY && handler instanceof BodyKeyDownHandler) + || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyDownHandler) + || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyDownHandler)) { + handler.onKeyDown(this); + } + } + + @Override + protected String getBrowserEventType() { + return BrowserEvents.KEYDOWN; + } + +} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java new file mode 100644 index 0000000000..6f06bc6674 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.google.gwt.dom.client.BrowserEvents; +import com.vaadin.client.ui.grid.Grid; +import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPressHandler; + +/** + * Represents native key press event in Grid. + * + * @since + * @author Vaadin Ltd + */ +public class GridKeyPressEvent extends + AbstractGridKeyEvent> { + + public GridKeyPressEvent(Grid grid) { + super(grid); + } + + @Override + protected void dispatch(GridKeyPressHandler handler) { + super.dispatch(handler); + if ((activeSection == GridSection.BODY && handler instanceof BodyKeyPressHandler) + || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyPressHandler) + || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyPressHandler)) { + handler.onKeyPress(this); + } + } + + @Override + protected String getBrowserEventType() { + return BrowserEvents.KEYPRESS; + } + +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java new file mode 100644 index 0000000000..d289dbae98 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.google.gwt.dom.client.BrowserEvents; +import com.vaadin.client.ui.grid.Grid; +import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUpHandler; + +/** + * Represents native key up event in Grid. + * + * @since + * @author Vaadin Ltd + */ +public class GridKeyUpEvent extends + AbstractGridKeyEvent> { + + public GridKeyUpEvent(Grid grid) { + super(grid); + } + + @Override + protected void dispatch(GridKeyUpHandler handler) { + super.dispatch(handler); + if ((activeSection == GridSection.BODY && handler instanceof BodyKeyUpHandler) + || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyUpHandler) + || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyUpHandler)) { + handler.onKeyUp(this); + } + } + + @Override + protected String getBrowserEventType() { + return BrowserEvents.KEYUP; + } + +} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java new file mode 100644 index 0000000000..28c9a8e056 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDownHandler; + +/** + * Handler for {@link GridKeyDownEvent}s that happen when active cell is in the + * header of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface HeaderKeyDownHandler extends GridKeyDownHandler { +} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java new file mode 100644 index 0000000000..607c30493d --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPressHandler; + +/** + * Handler for {@link GridKeyPressEvent}s that happen when active cell is in the + * header of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface HeaderKeyPressHandler extends GridKeyPressHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java new file mode 100644 index 0000000000..bfa3dde79b --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.keyevents; + +import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUpHandler; + +/** + * Handler for {@link GridKeyUpEvent}s that happen when active cell is in the + * header of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface HeaderKeyUpHandler extends GridKeyUpHandler { +} \ No newline at end of file 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..fe81380296 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientKeyEventsTest.java @@ -0,0 +1,108 @@ +/* + * 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.basicfeatures.GridBasicClientFeaturesTest; + +public class GridClientKeyEventsTest extends GridBasicClientFeaturesTest { + + private List 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()); + + } + } + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index 8a5a75da38..a7210236d4 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -25,8 +25,11 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HTML; +import com.vaadin.client.ui.VLabel; +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.Grid.AbstractGridKeyEvent; import com.vaadin.client.ui.grid.Grid.SelectionMode; import com.vaadin.client.ui.grid.GridColumn; import com.vaadin.client.ui.grid.GridFooter; @@ -36,6 +39,18 @@ 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.keyevents.BodyKeyDownHandler; +import com.vaadin.client.ui.grid.keyevents.BodyKeyPressHandler; +import com.vaadin.client.ui.grid.keyevents.BodyKeyUpHandler; +import com.vaadin.client.ui.grid.keyevents.FooterKeyDownHandler; +import com.vaadin.client.ui.grid.keyevents.FooterKeyPressHandler; +import com.vaadin.client.ui.grid.keyevents.FooterKeyUpHandler; +import com.vaadin.client.ui.grid.keyevents.GridKeyDownEvent; +import com.vaadin.client.ui.grid.keyevents.GridKeyPressEvent; +import com.vaadin.client.ui.grid.keyevents.GridKeyUpEvent; +import com.vaadin.client.ui.grid.keyevents.HeaderKeyDownHandler; +import com.vaadin.client.ui.grid.keyevents.HeaderKeyPressHandler; +import com.vaadin.client.ui.grid.keyevents.HeaderKeyUpHandler; import com.vaadin.client.ui.grid.renderers.DateRenderer; import com.vaadin.client.ui.grid.renderers.HtmlRenderer; import com.vaadin.client.ui.grid.renderers.NumberRenderer; @@ -236,7 +251,9 @@ public class GridBasicClientFeaturesWidget extends createFooterMenu(); grid.getElement().getStyle().setZIndex(0); - add(grid); + addNorth(grid, 400); + + createKeyHandlers(); } private void createStateMenu() { @@ -602,7 +619,7 @@ public class GridBasicClientFeaturesWidget extends } /** - * Creates a a renderer for a {@link Renderers} + * Creates a renderer for a {@link Renderers} */ @SuppressWarnings("rawtypes") private final Renderer createRenderer(Renderers renderer) { @@ -629,4 +646,110 @@ public class GridBasicClientFeaturesWidget extends return new TextRenderer(); } } + + /** + * Creates a collection of handlers for all the grid key events + */ + private void createKeyHandlers() { + final List labels = new ArrayList(); + for (int i = 0; i < 9; ++i) { + VLabel tmp = new VLabel(); + addNorth(tmp, 20); + labels.add(tmp); + } + + // Key Down Events + grid.addKeyDownHandler(new BodyKeyDownHandler>() { + private final VLabel label = labels.get(0); + + @Override + public void onKeyDown(GridKeyDownEvent> event) { + updateLabel(label, event); + } + }); + + grid.addKeyDownHandler(new HeaderKeyDownHandler>() { + private final VLabel label = labels.get(1); + + @Override + public void onKeyDown(GridKeyDownEvent> event) { + updateLabel(label, event); + } + }); + + grid.addKeyDownHandler(new FooterKeyDownHandler>() { + private final VLabel label = labels.get(2); + + @Override + public void onKeyDown(GridKeyDownEvent> event) { + updateLabel(label, event); + } + }); + + // Key Up Events + grid.addKeyUpHandler(new BodyKeyUpHandler>() { + private final VLabel label = labels.get(3); + + @Override + public void onKeyUp(GridKeyUpEvent> event) { + updateLabel(label, event); + } + }); + + grid.addKeyUpHandler(new HeaderKeyUpHandler>() { + private final VLabel label = labels.get(4); + + @Override + public void onKeyUp(GridKeyUpEvent> event) { + updateLabel(label, event); + } + }); + + grid.addKeyUpHandler(new FooterKeyUpHandler>() { + private final VLabel label = labels.get(5); + + @Override + public void onKeyUp(GridKeyUpEvent> event) { + updateLabel(label, event); + } + }); + + // Key Press Events + grid.addKeyPressHandler(new BodyKeyPressHandler>() { + private final VLabel label = labels.get(6); + + @Override + public void onKeyPress(GridKeyPressEvent> event) { + updateLabel(label, event); + } + }); + + grid.addKeyPressHandler(new HeaderKeyPressHandler>() { + private final VLabel label = labels.get(7); + + @Override + public void onKeyPress(GridKeyPressEvent> event) { + updateLabel(label, event); + } + }); + + grid.addKeyPressHandler(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); + } } -- cgit v1.2.3 From 32842a06a64d4351018ffb720d12aa8cd6011743 Mon Sep 17 00:00:00 2001 From: Patrik Lindström Date: Mon, 18 Aug 2014 16:04:28 +0300 Subject: Add event originator information to Sort Events (#13334) Change-Id: I9f8a295d6944807ccf89ea535d5500fac013e127 --- client/src/com/vaadin/client/ui/grid/Grid.java | 16 ++++++--- .../com/vaadin/client/ui/grid/GridConnector.java | 4 +-- .../com/vaadin/client/ui/grid/sort/SortEvent.java | 22 ++++++++++-- server/src/com/vaadin/ui/components/grid/Grid.java | 21 +++++++---- .../ui/components/grid/SortOrderChangeEvent.java | 21 ++++++++++- .../com/vaadin/shared/ui/grid/GridServerRpc.java | 3 +- .../vaadin/shared/ui/grid/SortEventOriginator.java | 41 ++++++++++++++++++++++ .../grid/basicfeatures/GridBasicFeatures.java | 19 +++++++++- .../grid/basicfeatures/server/GridSortingTest.java | 20 ++++++++--- 9 files changed, 142 insertions(+), 25 deletions(-) create mode 100644 shared/src/com/vaadin/shared/ui/grid/SortEventOriginator.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index a2bb0d3f09..22c3604bf8 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -87,6 +87,7 @@ import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.Range; import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.shared.ui.grid.SortDirection; +import com.vaadin.shared.ui.grid.SortEventOriginator; /** * A data grid view that supports columns and lazy loading of data rows from a @@ -622,8 +623,8 @@ public class Grid extends Composite implements } } - // Perform sorting - Grid.this.sort(sorting); + // Perform sorting; indicate originator as user + Grid.this.setSortOrder(sorting.build(), SortEventOriginator.USER); } } @@ -2376,11 +2377,16 @@ public class Grid extends Composite implements * a sort order list. If set to null, the sort order is cleared. */ public void setSortOrder(List order) { + setSortOrder(order, SortEventOriginator.API); + } + + private void setSortOrder(List order, + SortEventOriginator originator) { sortOrder.clear(); if (order != null) { sortOrder.addAll(order); } - sort(); + sort(originator); } /** @@ -2505,9 +2511,9 @@ public class Grid extends Composite implements /** * Apply sorting to data source. */ - private void sort() { + private void sort(SortEventOriginator originator) { refreshHeader(); fireEvent(new SortEvent(this, - Collections.unmodifiableList(sortOrder))); + Collections.unmodifiableList(sortOrder), originator)); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 9d93c81d82..73440232b1 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -224,8 +224,8 @@ public class GridConnector extends AbstractHasComponentsConnector { if (!Arrays.equals(columnIds, getState().sortColumns) || !Arrays.equals(directions, getState().sortDirs)) { // Report back to server if changed - getRpcProxy(GridServerRpc.class) - .sort(columnIds, directions); + getRpcProxy(GridServerRpc.class).sort(columnIds, + directions, event.getOriginator()); } } }); diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java b/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java index baa12ae224..edbd84c4a5 100644 --- a/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java +++ b/client/src/com/vaadin/client/ui/grid/sort/SortEvent.java @@ -20,6 +20,7 @@ import java.util.List; import com.google.gwt.event.shared.GwtEvent; import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.grid.Grid; +import com.vaadin.shared.ui.grid.SortEventOriginator; /** * A sort event, fired by the Grid when it needs its data source to provide data @@ -34,6 +35,7 @@ public class SortEvent extends GwtEvent> { private final Grid grid; private final List order; + private final SortEventOriginator originator; /** * Creates a new Sort Event. All provided parameters are final, and passed @@ -41,14 +43,16 @@ public class SortEvent extends GwtEvent> { * * @param grid * a grid reference - * @param datasource - * a reference to the grid's data source * @param order * an array dictating the desired sort order of the data source + * @param originator + * a value indicating where this event originated from */ - public SortEvent(Grid grid, List order) { + public SortEvent(Grid grid, List order, + SortEventOriginator originator) { this.grid = grid; this.order = order; + this.originator = originator; } @Override @@ -103,6 +107,18 @@ public class SortEvent extends GwtEvent> { return order; } + /** + * Gets a value describing the originator of this event, i.e. what actions + * resulted in this event being fired. + * + * @return a sort event originator value + * + * @see SortEventOriginator + */ + public SortEventOriginator getOriginator() { + return originator; + } + @SuppressWarnings("unchecked") @Override protected void dispatch(SortEventHandler handler) { diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index fba6eed462..3c115f9241 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -49,6 +49,7 @@ import com.vaadin.shared.ui.grid.GridStaticCellType; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.shared.ui.grid.SortDirection; +import com.vaadin.shared.ui.grid.SortEventOriginator; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Component; import com.vaadin.ui.HasComponents; @@ -373,7 +374,8 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, } @Override - public void sort(String[] columnIds, SortDirection[] directions) { + public void sort(String[] columnIds, SortDirection[] directions, + SortEventOriginator originator) { assert columnIds.length == directions.length; List order = new ArrayList( @@ -383,7 +385,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, order.add(new SortOrder(propertyId, directions[i])); } - setSortOrder(order); + setSortOrder(order, originator); } }); } @@ -439,7 +441,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, } } - sort(); + sort(SortEventOriginator.INTERNAL); } else { // If the new container is not sortable, we'll just re-set the sort @@ -1126,7 +1128,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, */ public void clearSortOrder() { sortOrder.clear(); - sort(); + sort(false); } /** @@ -1140,6 +1142,11 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, * a sort order list. */ public void setSortOrder(List order) { + setSortOrder(order, SortEventOriginator.API); + } + + private void setSortOrder(List order, + SortEventOriginator originator) { if (!(getContainerDatasource() instanceof Container.Sortable)) { throw new IllegalStateException( "Attached container is not sortable (does not implement Container.Sortable)"); @@ -1164,7 +1171,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, } sortOrder.addAll(order); - sort(); + sort(originator); } /** @@ -1179,7 +1186,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, /** * Apply sorting to data source. */ - private void sort() { + private void sort(SortEventOriginator originator) { Container c = getContainerDatasource(); if (c instanceof Container.Sortable) { @@ -1215,7 +1222,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, cs.sort(propertyIds, directions); fireEvent(new SortOrderChangeEvent(this, new ArrayList( - sortOrder))); + sortOrder), originator)); getState().sortColumns = columnKeys; getState(false).sortDirs = stateDirs; diff --git a/server/src/com/vaadin/ui/components/grid/SortOrderChangeEvent.java b/server/src/com/vaadin/ui/components/grid/SortOrderChangeEvent.java index 71afa10a9b..690fcdf1c4 100644 --- a/server/src/com/vaadin/ui/components/grid/SortOrderChangeEvent.java +++ b/server/src/com/vaadin/ui/components/grid/SortOrderChangeEvent.java @@ -17,6 +17,7 @@ package com.vaadin.ui.components.grid; import java.util.List; +import com.vaadin.shared.ui.grid.SortEventOriginator; import com.vaadin.ui.Component; import com.vaadin.ui.components.grid.sort.SortOrder; @@ -31,6 +32,7 @@ import com.vaadin.ui.components.grid.sort.SortOrder; public class SortOrderChangeEvent extends Component.Event { private final List sortOrder; + private final SortEventOriginator originator; /** * Creates a new sort order change event for a grid and a sort order list. @@ -39,10 +41,15 @@ public class SortOrderChangeEvent extends Component.Event { * the grid from which the event originates * @param sortOrder * the new sort order list + * @param wasInitiatedByUser + * should be set to true if this event results from end-user + * interaction instead of an API call or side effect */ - public SortOrderChangeEvent(Grid grid, List sortOrder) { + public SortOrderChangeEvent(Grid grid, List sortOrder, + SortEventOriginator originator) { super(grid); this.sortOrder = sortOrder; + this.originator = originator; } /** @@ -54,4 +61,16 @@ public class SortOrderChangeEvent extends Component.Event { return sortOrder; } + /** + * Gets a value describing the originator of this event, i.e. what actions + * resulted in this event being fired. + * + * @return a sort event originator value + * + * @see SortEventOriginator + */ + public SortEventOriginator getOriginator() { + return originator; + } + } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java index 9ce094b092..fd671e30a7 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java @@ -28,5 +28,6 @@ import com.vaadin.shared.communication.ServerRpc; public interface GridServerRpc extends ServerRpc { void selectionChange(List newSelection); - void sort(String[] columnIds, SortDirection[] directions); + void sort(String[] columnIds, SortDirection[] directions, + SortEventOriginator originator); } diff --git a/shared/src/com/vaadin/shared/ui/grid/SortEventOriginator.java b/shared/src/com/vaadin/shared/ui/grid/SortEventOriginator.java new file mode 100644 index 0000000000..acdd46ea5b --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/SortEventOriginator.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.shared.ui.grid; + +/** + * Identifier for the originator of a sort event or sort order change event. + * + * @since + * @author Vaadin Ltd + */ +public enum SortEventOriginator { + + /** + * This event was the result of an API call. + */ + API, + + /** + * This event was the result of a user interacting with the UI. + */ + USER, + + /** + * This event resulted as a side-effect of an internal event. + */ + INTERNAL + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 031ebf7fa5..d54b1838ea 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -168,7 +168,24 @@ public class GridBasicFeatures extends AbstractComponentTest { grid.addSortOrderChangeListener(new SortOrderChangeListener() { @Override public void sortOrderChange(SortOrderChangeEvent event) { - log("Sort order: " + event.getSortOrder()); + + 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); } }); 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 index a5a83c156e..024be65e83 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java @@ -42,6 +42,11 @@ public class GridSortingTest extends GridBasicFeaturesTest { // 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")); @@ -119,14 +124,17 @@ public class GridSortingTest extends GridBasicFeaturesTest { "(" + row + ", 0)", grid.getCell(i, 0).getText()); } - assertEquals("2. Sort order: [Column 9 ASCENDING]", getLogRow(2)); - assertEquals("4. Sort order: [Column 9 DESCENDING]", getLogRow(0)); + 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]", getLogRow(0)); + assertEquals("6. Sort order: [Column 10 ASCENDING] by USER", + getLogRow(0)); // Not cleaning up correctly causes exceptions when scrolling. grid.scrollToRow(50); @@ -153,8 +161,10 @@ public class GridSortingTest extends GridBasicFeaturesTest { grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText()); } - assertEquals("9. Sort order: [Column 7 ASCENDING]", getLogRow(3)); - assertEquals("11. Sort order: [Column 7 DESCENDING]", getLogRow(1)); + assertEquals("9. Sort order: [Column 7 ASCENDING] by USER", + getLogRow(3)); + assertEquals("11. Sort order: [Column 7 DESCENDING] by USER", + getLogRow(1)); } @Test -- cgit v1.2.3 From 204b16013ccc129dc4ce78cab73a51a65f5bf4c8 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Wed, 13 Aug 2014 14:02:42 +0300 Subject: Added PAGEUP/PAGEDOWN/HOME/END keyboard navigation #13334 Change-Id: Ib415d4b3abcefc11983f2daa8cb11a2bdd99b95a --- client/src/com/vaadin/client/ui/grid/Grid.java | 100 +++++++++++++++------ .../server/GridKeyboardNavigationTest.java | 55 +++++++++++- 2 files changed, 129 insertions(+), 26 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 22c3604bf8..0e077f4867 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -454,31 +454,6 @@ public class Grid extends Composite implements } - private int getLastVisibleRowIndex() { - int lastRowIndex = escalator.getVisibleRowRange().getEnd(); - int footerTop = escalator.getFooter().getElement().getAbsoluteTop(); - Element lastRow; - - do { - lastRow = escalator.getBody().getRowElement(--lastRowIndex); - } while (lastRow.getAbsoluteBottom() > footerTop); - - return lastRowIndex; - } - - private int getFirstVisibleRowIndex() { - int firstRowIndex = escalator.getVisibleRowRange().getStart(); - int headerBottom = escalator.getHeader().getElement() - .getAbsoluteBottom(); - Element firstRow = escalator.getBody().getRowElement(firstRowIndex); - - while (firstRow.getAbsoluteTop() < headerBottom) { - firstRow = escalator.getBody().getRowElement(++firstRowIndex); - } - - return firstRowIndex; - } - private RowContainer getPreviousContainer(RowContainer current) { if (current == escalator.getFooter()) { current = escalator.getBody(); @@ -1984,9 +1959,59 @@ public class Grid extends Composite implements && (Util.getFocusedElement() == getElement() || cell != null)) { activeCellHandler.handleNavigationEvent(event, cell); } + + handleGridNavigation(event, cell); } } + private void handleGridNavigation(Event event, Cell cell) { + if (!event.getType().equals(BrowserEvents.KEYDOWN)) { + // Only handle key downs + return; + } + + int newRow = -1; + RowContainer container = escalator.getBody(); + switch (event.getKeyCode()) { + case KeyCodes.KEY_HOME: + if (container.getRowCount() > 0) { + newRow = 0; + } + break; + case KeyCodes.KEY_END: + if (container.getRowCount() > 0) { + newRow = container.getRowCount() - 1; + } + break; + case KeyCodes.KEY_PAGEUP: { + Range range = escalator.getVisibleRowRange(); + if (!range.isEmpty()) { + int firstIndex = getFirstVisibleRowIndex(); + newRow = firstIndex - range.length(); + if (newRow < 0) { + newRow = 0; + } + } + break; + } + case KeyCodes.KEY_PAGEDOWN: { + Range range = escalator.getVisibleRowRange(); + if (!range.isEmpty()) { + int lastIndex = getLastVisibleRowIndex(); + newRow = lastIndex + range.length(); + if (newRow >= container.getRowCount()) { + newRow = container.getRowCount() - 1; + } + } + break; + } + default: + return; + } + + scrollToRow(newRow); + } + private Point rowEventTouchStartingPoint; private boolean handleDefaultRowEvent(final Cell cell, NativeEvent event) { @@ -2516,4 +2541,29 @@ public class Grid extends Composite implements fireEvent(new SortEvent(this, Collections.unmodifiableList(sortOrder), originator)); } + + private int getLastVisibleRowIndex() { + int lastRowIndex = escalator.getVisibleRowRange().getEnd(); + int footerTop = escalator.getFooter().getElement().getAbsoluteTop(); + Element lastRow; + + do { + lastRow = escalator.getBody().getRowElement(--lastRowIndex); + } while (lastRow.getAbsoluteBottom() > footerTop); + + return lastRowIndex; + } + + private int getFirstVisibleRowIndex() { + int firstRowIndex = escalator.getVisibleRowRange().getStart(); + int headerBottom = escalator.getHeader().getElement() + .getAbsoluteBottom(); + Element firstRow = escalator.getBody().getRowElement(firstRowIndex); + + while (firstRow.getAbsoluteTop() < headerBottom) { + firstRow = escalator.getBody().getRowElement(++firstRowIndex); + } + + return firstRowIndex; + } } 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 index 948c753fec..0f9fd875d8 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridKeyboardNavigationTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridKeyboardNavigationTest.java @@ -24,7 +24,7 @@ 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.GridBasicFeaturesTest; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures; import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { @@ -169,4 +169,57 @@ public class GridKeyboardNavigationTest extends GridBasicFeaturesTest { 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()); + + } + } -- cgit v1.2.3 From d9ff10864bc17bfd6e83725a293065b91d234904 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 19 Aug 2014 11:36:41 +0300 Subject: Implement selection with keyboard (#13334) Change-Id: I29a2ac38dfd613e952fd2f939ee8670271255aa3 --- client/src/com/vaadin/client/ui/grid/Grid.java | 5 ++ .../client/ui/grid/renderers/ComplexRenderer.java | 8 +++ .../ui/grid/selection/MultiSelectionRenderer.java | 67 ++++++++++++++++++++++ .../basicfeatures/server/GridSelectionTest.java | 28 +++++++++ 4 files changed, 108 insertions(+) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index cf802b5d48..70d8286c90 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -2222,6 +2222,11 @@ public class Grid extends Composite implements throw new IllegalArgumentException("Selection model can't be null"); } + if (selectColumnRenderer != null + && selectColumnRenderer instanceof ComplexRenderer) { + ((ComplexRenderer) selectColumnRenderer).destroy(); + } + this.selectionModel = selectionModel; selectionModel.setGrid(this); setSelectColumnRenderer(this.selectionModel diff --git a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java index d5dd845e92..f0c95e2ddf 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java @@ -142,4 +142,12 @@ public abstract class ComplexRenderer implements Renderer { public boolean onActivate() { return false; } + + /** + * Called when the renderer is deemed to be destroyed and no longer used by + * the Grid. + */ + public void destroy() { + // Implement if needed + } } diff --git a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java index 1033b00623..a3030e3a1f 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java @@ -27,6 +27,7 @@ import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.InputElement; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.TableElement; +import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; @@ -36,10 +37,17 @@ import com.vaadin.client.Util; import com.vaadin.client.data.AbstractRemoteDataSource; import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.grid.Cell; +import com.vaadin.client.ui.grid.DataAvailableEvent; +import com.vaadin.client.ui.grid.DataAvailableHandler; import com.vaadin.client.ui.grid.FlyweightCell; import com.vaadin.client.ui.grid.Grid; +import com.vaadin.client.ui.grid.keyevents.BodyKeyDownHandler; +import com.vaadin.client.ui.grid.keyevents.BodyKeyUpHandler; +import com.vaadin.client.ui.grid.keyevents.GridKeyDownEvent; +import com.vaadin.client.ui.grid.keyevents.GridKeyUpEvent; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.selection.SelectionModel.Multi.Batched; +import com.vaadin.shared.ui.grid.ScrollDestination; /* This class will probably not survive the final merge of all selection functionality. */ public class MultiSelectionRenderer extends ComplexRenderer { @@ -576,15 +584,74 @@ public class MultiSelectionRenderer extends ComplexRenderer { } } + private class SpaceKeyDownSelectHandler implements BodyKeyDownHandler { + + private HandlerRegistration scrollHandler = null; + private boolean spaceDown = false; + + @Override + public void onKeyDown(GridKeyDownEvent event) { + if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE || spaceDown) { + return; + } + + spaceDown = true; + Cell active = event.getActiveCell(); + final int rowIndex = active.getRow(); + + if (scrollHandler != null) { + scrollHandler.removeHandler(); + scrollHandler = null; + } + + scrollHandler = grid + .addDataAvailableHandler(new DataAvailableHandler() { + + @Override + public void onDataAvailable(DataAvailableEvent event) { + if (event.getAvailableRows().contains(rowIndex)) { + setSelected(rowIndex, !isSelected(rowIndex)); + scrollHandler.removeHandler(); + scrollHandler = null; + } + } + }); + grid.scrollToRow(rowIndex, ScrollDestination.ANY); + } + + } + private static final String LOGICAL_ROW_PROPERTY_INT = "vEscalatorLogicalRow"; private final Grid grid; private HandlerRegistration nativePreviewHandlerRegistration; + private final SpaceKeyDownSelectHandler handler = new SpaceKeyDownSelectHandler(); + private HandlerRegistration spaceDown; + private HandlerRegistration spaceUp; private final AutoScrollHandler autoScrollHandler = new AutoScrollHandler(); public MultiSelectionRenderer(final Grid grid) { this.grid = grid; + spaceDown = grid.addKeyDownHandler(handler); + spaceUp = grid.addKeyUpHandler(new BodyKeyUpHandler() { + + @Override + public void onKeyUp(GridKeyUpEvent event) { + if (event.getNativeKeyCode() == KeyCodes.KEY_SPACE) { + handler.spaceDown = false; + } + } + }); + } + + @Override + public void destroy() { + spaceDown.removeHandler(); + spaceUp.removeHandler(); + if (nativePreviewHandlerRegistration != null) { + removeNativeHandler(); + } } @Override 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 index c190f7d0ec..6e2ac91df2 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java @@ -19,6 +19,8 @@ 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; @@ -123,6 +125,32 @@ public class GridSelectionTest extends GridBasicFeaturesTest { 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"); } -- cgit v1.2.3 From 04d6842bb7fc4d288c3cc07966988f55cf6841a4 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Tue, 26 Aug 2014 14:39:48 +0300 Subject: Fixes "add first row" action (#13334) Change-Id: I23e2dcbf5d7e0801ae63e02126eee8e85726eefc --- .../grid/basicfeatures/GridBasicFeatures.java | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index d54b1838ea..a862aa095f 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -561,10 +561,28 @@ public class GridBasicFeatures extends AbstractComponentTest { public void execute(Grid c, String value, Object data) { Item item = ds.addItemAt(0, new Object()); for (int i = 0; i < COLUMNS; i++) { - item.getItemProperty(getColumnProperty(i)) - .setValue("newcell: " + i); + Class type = ds.getType(getColumnProperty(i)); + if (String.class.isAssignableFrom(type)) { + Property itemProperty = getProperty( + item, i); + itemProperty.setValue("newcell: " + i); + } else if (Integer.class.isAssignableFrom(type)) { + Property itemProperty = getProperty( + item, i); + itemProperty.setValue(Integer.valueOf(i)); + } else { + // let the default value be taken implicitly. + } } } + + private Property getProperty( + Item item, int i) { + @SuppressWarnings("unchecked") + Property itemProperty = item + .getItemProperty(getColumnProperty(i)); + return itemProperty; + } }, null); createClickAction("Remove first row", "Body rows", -- cgit v1.2.3 From c0897e9b8b1eabe3dc40141ea4a285dc404080ba Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 26 Aug 2014 13:21:37 +0300 Subject: Fix Grid Footer to be visible by default (#13334) Change-Id: Ib2cc3be7b935bfbe78b34cd05c41d9d42292926d --- server/src/com/vaadin/ui/components/grid/GridFooter.java | 1 - .../src/com/vaadin/tests/server/component/grid/GridColumns.java | 8 ++++---- uitest/src/com/vaadin/tests/components/grid/GridColspans.java | 2 -- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'uitest/src') diff --git a/server/src/com/vaadin/ui/components/grid/GridFooter.java b/server/src/com/vaadin/ui/components/grid/GridFooter.java index 0a28a481cf..2af991a39c 100644 --- a/server/src/com/vaadin/ui/components/grid/GridFooter.java +++ b/server/src/com/vaadin/ui/components/grid/GridFooter.java @@ -50,7 +50,6 @@ public class GridFooter extends GridStaticSection { protected GridFooter(Grid grid) { this.grid = grid; grid.getState(true).footer = footerState; - setVisible(false); } @Override diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java index d1c821cc54..d7f29b8014 100644 --- a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java +++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java @@ -185,16 +185,16 @@ public class GridColumns { @Test public void testFooterVisibility() throws Exception { - assertFalse(grid.getFooter().isVisible()); - assertFalse(state.footer.visible); - - grid.getFooter().setVisible(true); assertTrue(grid.getFooter().isVisible()); assertTrue(state.footer.visible); grid.getFooter().setVisible(false); assertFalse(grid.getFooter().isVisible()); assertFalse(state.footer.visible); + + grid.getFooter().setVisible(true); + assertTrue(grid.getFooter().isVisible()); + assertTrue(state.footer.visible); } @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/GridColspans.java b/uitest/src/com/vaadin/tests/components/grid/GridColspans.java index be12c2bcb2..7b905d5404 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridColspans.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridColspans.java @@ -64,8 +64,6 @@ public class GridColspans extends AbstractTestUI { footerRow.join("streetAddress", "zipCode", "city").setText("Address"); footer.appendRow().join(dataSource.getContainerPropertyIds().toArray()) .setText("All the stuff"); - - footer.setVisible(true); } @Override -- cgit v1.2.3 From ec2ecdf0e79ee3c13f0e16192c8000930e525e8a Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 26 Aug 2014 15:05:59 +0300 Subject: Remove type parameters from GridKeyEvents (#13334) Change-Id: I8132c034ec378bae91574535f6f1b20591f46d1e --- client/src/com/vaadin/client/ui/grid/Grid.java | 20 +++++------ .../keyevents/AbstractGridKeyEventHandler.java | 13 ++++---- .../ui/grid/keyevents/BodyKeyDownHandler.java | 2 +- .../ui/grid/keyevents/BodyKeyPressHandler.java | 2 +- .../client/ui/grid/keyevents/BodyKeyUpHandler.java | 2 +- .../ui/grid/keyevents/FooterKeyDownHandler.java | 2 +- .../ui/grid/keyevents/FooterKeyPressHandler.java | 2 +- .../ui/grid/keyevents/FooterKeyUpHandler.java | 2 +- .../client/ui/grid/keyevents/GridKeyDownEvent.java | 7 ++-- .../ui/grid/keyevents/GridKeyPressEvent.java | 8 ++--- .../client/ui/grid/keyevents/GridKeyUpEvent.java | 7 ++-- .../ui/grid/keyevents/HeaderKeyDownHandler.java | 2 +- .../ui/grid/keyevents/HeaderKeyPressHandler.java | 2 +- .../ui/grid/keyevents/HeaderKeyUpHandler.java | 2 +- .../ui/grid/selection/MultiSelectionRenderer.java | 8 ++--- .../client/grid/GridBasicClientFeaturesWidget.java | 39 +++++++++++----------- 16 files changed, 59 insertions(+), 61 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 70d8286c90..4efe42a825 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -124,7 +124,7 @@ import com.vaadin.shared.ui.grid.SortEventOriginator; public class Grid extends Composite implements HasSelectionChangeHandlers, SubPartAware { - public static abstract class AbstractGridKeyEvent + public static abstract class AbstractGridKeyEvent extends KeyCodeEvent { /** @@ -134,13 +134,13 @@ public class Grid extends Composite implements HEADER, BODY, FOOTER } - private Grid grid; + private Grid grid; protected Cell activeCell; protected GridSection activeSection; private final Type associatedType = new Type( getBrowserEventType(), this); - public AbstractGridKeyEvent(Grid grid) { + public AbstractGridKeyEvent(Grid grid) { this.grid = grid; } @@ -151,7 +151,7 @@ public class Grid extends Composite implements * * @return grid */ - public Grid getGrid() { + public Grid getGrid() { return grid; } @@ -182,9 +182,9 @@ public class Grid extends Composite implements } } - private GridKeyDownEvent keyDown = new GridKeyDownEvent(this); - private GridKeyUpEvent keyUp = new GridKeyUpEvent(this); - private GridKeyPressEvent keyPress = new GridKeyPressEvent(this); + private GridKeyDownEvent keyDown = new GridKeyDownEvent(this); + private GridKeyUpEvent keyUp = new GridKeyUpEvent(this); + private GridKeyPressEvent keyPress = new GridKeyPressEvent(this); private class ActiveCellHandler { @@ -2475,7 +2475,7 @@ public class Grid extends Composite implements * the key handler to register * @return the registration for the event */ - public > HandlerRegistration addKeyDownHandler( + public HandlerRegistration addKeyDownHandler( HANDLER handler) { if (handler instanceof BodyKeyDownHandler || handler instanceof HeaderKeyDownHandler @@ -2495,7 +2495,7 @@ public class Grid extends Composite implements * the key handler to register * @return the registration for the event */ - public > HandlerRegistration addKeyUpHandler( + public HandlerRegistration addKeyUpHandler( HANDLER handler) { if (handler instanceof BodyKeyUpHandler || handler instanceof HeaderKeyUpHandler @@ -2515,7 +2515,7 @@ public class Grid extends Composite implements * the key handler to register * @return the registration for the event */ - public > HandlerRegistration addKeyPressHandler( + public HandlerRegistration addKeyPressHandler( HANDLER handler) { if (handler instanceof BodyKeyPressHandler || handler instanceof HeaderKeyPressHandler diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java index 28a85924fa..57708e8bc9 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java @@ -16,6 +16,7 @@ package com.vaadin.client.ui.grid.keyevents; import com.google.gwt.event.shared.EventHandler; +import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; /** * Base interface of all handlers for {@link AbstractGridKeyEvent}s. @@ -25,19 +26,19 @@ import com.google.gwt.event.shared.EventHandler; */ public abstract interface AbstractGridKeyEventHandler extends EventHandler { - public abstract interface GridKeyDownHandler extends + public abstract interface GridKeyDownHandler extends AbstractGridKeyEventHandler { - public void onKeyDown(GridKeyDownEvent event); + public void onKeyDown(GridKeyDownEvent event); } - public abstract interface GridKeyUpHandler extends + public abstract interface GridKeyUpHandler extends AbstractGridKeyEventHandler { - public void onKeyUp(GridKeyUpEvent event); + public void onKeyUp(GridKeyUpEvent event); } - public abstract interface GridKeyPressHandler extends + public abstract interface GridKeyPressHandler extends AbstractGridKeyEventHandler { - public void onKeyPress(GridKeyPressEvent event); + public void onKeyPress(GridKeyPressEvent event); } } diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java index a3b76ea5d7..9e61624a28 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java @@ -24,5 +24,5 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDo * @since * @author Vaadin Ltd */ -public interface BodyKeyDownHandler extends GridKeyDownHandler { +public interface BodyKeyDownHandler extends GridKeyDownHandler { } diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java index 5548994cf9..f44c1d172e 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java @@ -24,5 +24,5 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPr * @since * @author Vaadin Ltd */ -public interface BodyKeyPressHandler extends GridKeyPressHandler { +public interface BodyKeyPressHandler extends GridKeyPressHandler { } \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java index 33b4fc81fe..a6b3929d80 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java @@ -24,5 +24,5 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUp * @since * @author Vaadin Ltd */ -public interface BodyKeyUpHandler extends GridKeyUpHandler { +public interface BodyKeyUpHandler extends GridKeyUpHandler { } \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java index e90f52e736..5e9fffdcda 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java @@ -24,5 +24,5 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDo * @since * @author Vaadin Ltd */ -public interface FooterKeyDownHandler extends GridKeyDownHandler { +public interface FooterKeyDownHandler extends GridKeyDownHandler { } diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java index 58f48f36f5..d5713d9135 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java @@ -24,5 +24,5 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPr * @since * @author Vaadin Ltd */ -public interface FooterKeyPressHandler extends GridKeyPressHandler { +public interface FooterKeyPressHandler extends GridKeyPressHandler { } \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java index d6bcddf710..87978e1cd2 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java @@ -24,5 +24,5 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUp * @since * @author Vaadin Ltd */ -public interface FooterKeyUpHandler extends GridKeyUpHandler { +public interface FooterKeyUpHandler extends GridKeyUpHandler { } \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java index 8af65dbf49..65c8327eb6 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java @@ -26,15 +26,14 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDo * @since * @author Vaadin Ltd */ -public class GridKeyDownEvent extends - AbstractGridKeyEvent> { +public class GridKeyDownEvent extends AbstractGridKeyEvent { - public GridKeyDownEvent(Grid grid) { + public GridKeyDownEvent(Grid grid) { super(grid); } @Override - protected void dispatch(GridKeyDownHandler handler) { + protected void dispatch(GridKeyDownHandler handler) { super.dispatch(handler); if ((activeSection == GridSection.BODY && handler instanceof BodyKeyDownHandler) || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyDownHandler) diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java index 6f06bc6674..388467990b 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java @@ -26,15 +26,15 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPr * @since * @author Vaadin Ltd */ -public class GridKeyPressEvent extends - AbstractGridKeyEvent> { +public class GridKeyPressEvent extends + AbstractGridKeyEvent { - public GridKeyPressEvent(Grid grid) { + public GridKeyPressEvent(Grid grid) { super(grid); } @Override - protected void dispatch(GridKeyPressHandler handler) { + protected void dispatch(GridKeyPressHandler handler) { super.dispatch(handler); if ((activeSection == GridSection.BODY && handler instanceof BodyKeyPressHandler) || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyPressHandler) diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java index d289dbae98..dd1fb33e3f 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java @@ -26,15 +26,14 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUp * @since * @author Vaadin Ltd */ -public class GridKeyUpEvent extends - AbstractGridKeyEvent> { +public class GridKeyUpEvent extends AbstractGridKeyEvent { - public GridKeyUpEvent(Grid grid) { + public GridKeyUpEvent(Grid grid) { super(grid); } @Override - protected void dispatch(GridKeyUpHandler handler) { + protected void dispatch(GridKeyUpHandler handler) { super.dispatch(handler); if ((activeSection == GridSection.BODY && handler instanceof BodyKeyUpHandler) || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyUpHandler) diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java index 28c9a8e056..d8a1132a84 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java @@ -24,5 +24,5 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDo * @since * @author Vaadin Ltd */ -public interface HeaderKeyDownHandler extends GridKeyDownHandler { +public interface HeaderKeyDownHandler extends GridKeyDownHandler { } diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java index 607c30493d..a2245b1dfe 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java @@ -24,5 +24,5 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPr * @since * @author Vaadin Ltd */ -public interface HeaderKeyPressHandler extends GridKeyPressHandler { +public interface HeaderKeyPressHandler extends GridKeyPressHandler { } \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java index bfa3dde79b..405195ec94 100644 --- a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java +++ b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java @@ -24,5 +24,5 @@ import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUp * @since * @author Vaadin Ltd */ -public interface HeaderKeyUpHandler extends GridKeyUpHandler { +public interface HeaderKeyUpHandler extends GridKeyUpHandler { } \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java index a3030e3a1f..bfcc639a64 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java @@ -584,13 +584,13 @@ public class MultiSelectionRenderer extends ComplexRenderer { } } - private class SpaceKeyDownSelectHandler implements BodyKeyDownHandler { + private class SpaceKeyDownSelectHandler implements BodyKeyDownHandler { private HandlerRegistration scrollHandler = null; private boolean spaceDown = false; @Override - public void onKeyDown(GridKeyDownEvent event) { + public void onKeyDown(GridKeyDownEvent event) { if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE || spaceDown) { return; } @@ -634,10 +634,10 @@ public class MultiSelectionRenderer extends ComplexRenderer { public MultiSelectionRenderer(final Grid grid) { this.grid = grid; spaceDown = grid.addKeyDownHandler(handler); - spaceUp = grid.addKeyUpHandler(new BodyKeyUpHandler() { + spaceUp = grid.addKeyUpHandler(new BodyKeyUpHandler() { @Override - public void onKeyUp(GridKeyUpEvent event) { + public void onKeyUp(GridKeyUpEvent event) { if (event.getNativeKeyCode() == KeyCodes.KEY_SPACE) { handler.spaceDown = false; } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index a7210236d4..1bdbd76a20 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -659,93 +659,92 @@ public class GridBasicClientFeaturesWidget extends } // Key Down Events - grid.addKeyDownHandler(new BodyKeyDownHandler>() { + grid.addKeyDownHandler(new BodyKeyDownHandler() { private final VLabel label = labels.get(0); @Override - public void onKeyDown(GridKeyDownEvent> event) { + public void onKeyDown(GridKeyDownEvent event) { updateLabel(label, event); } }); - grid.addKeyDownHandler(new HeaderKeyDownHandler>() { + grid.addKeyDownHandler(new HeaderKeyDownHandler() { private final VLabel label = labels.get(1); @Override - public void onKeyDown(GridKeyDownEvent> event) { + public void onKeyDown(GridKeyDownEvent event) { updateLabel(label, event); } }); - grid.addKeyDownHandler(new FooterKeyDownHandler>() { + grid.addKeyDownHandler(new FooterKeyDownHandler() { private final VLabel label = labels.get(2); @Override - public void onKeyDown(GridKeyDownEvent> event) { + public void onKeyDown(GridKeyDownEvent event) { updateLabel(label, event); } }); // Key Up Events - grid.addKeyUpHandler(new BodyKeyUpHandler>() { + grid.addKeyUpHandler(new BodyKeyUpHandler() { private final VLabel label = labels.get(3); @Override - public void onKeyUp(GridKeyUpEvent> event) { + public void onKeyUp(GridKeyUpEvent event) { updateLabel(label, event); } }); - grid.addKeyUpHandler(new HeaderKeyUpHandler>() { + grid.addKeyUpHandler(new HeaderKeyUpHandler() { private final VLabel label = labels.get(4); @Override - public void onKeyUp(GridKeyUpEvent> event) { + public void onKeyUp(GridKeyUpEvent event) { updateLabel(label, event); } }); - grid.addKeyUpHandler(new FooterKeyUpHandler>() { + grid.addKeyUpHandler(new FooterKeyUpHandler() { private final VLabel label = labels.get(5); @Override - public void onKeyUp(GridKeyUpEvent> event) { + public void onKeyUp(GridKeyUpEvent event) { updateLabel(label, event); } }); // Key Press Events - grid.addKeyPressHandler(new BodyKeyPressHandler>() { + grid.addKeyPressHandler(new BodyKeyPressHandler() { private final VLabel label = labels.get(6); @Override - public void onKeyPress(GridKeyPressEvent> event) { + public void onKeyPress(GridKeyPressEvent event) { updateLabel(label, event); } }); - grid.addKeyPressHandler(new HeaderKeyPressHandler>() { + grid.addKeyPressHandler(new HeaderKeyPressHandler() { private final VLabel label = labels.get(7); @Override - public void onKeyPress(GridKeyPressEvent> event) { + public void onKeyPress(GridKeyPressEvent event) { updateLabel(label, event); } }); - grid.addKeyPressHandler(new FooterKeyPressHandler>() { + grid.addKeyPressHandler(new FooterKeyPressHandler() { private final VLabel label = labels.get(8); @Override - public void onKeyPress(GridKeyPressEvent> event) { + public void onKeyPress(GridKeyPressEvent event) { updateLabel(label, event); } }); } - private void updateLabel(VLabel label, - AbstractGridKeyEvent, ?> event) { + private void updateLabel(VLabel label, AbstractGridKeyEvent event) { String type = event.getNativeEvent().getType(); Cell active = event.getActiveCell(); String coords = "(" + active.getRow() + ", " + active.getColumn() + ")"; -- cgit v1.2.3 From b49e431840030436bdcecfb0cff3ff38b6509b6b Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 28 Aug 2014 09:17:02 +0300 Subject: Fix GridBasicFeatures to use correct property IDs Change-Id: I385fc841b5a46c55f9a28197837616e597891fb1 --- .../grid/basicfeatures/GridBasicFeatures.java | 32 +++++----------------- 1 file changed, 7 insertions(+), 25 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index a862aa095f..87109b5007 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -18,7 +18,6 @@ package com.vaadin.tests.components.grid.basicfeatures; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; @@ -386,10 +385,7 @@ public class GridBasicFeatures extends AbstractComponentTest { @Override public void execute(Grid grid, Boolean value, Object columnIndex) { - Object propertyId = (new ArrayList(grid - .getContainerDatasource() - .getContainerPropertyIds()) - .get((Integer) columnIndex)); + Object propertyId = getColumnProperty((Integer) columnIndex); GridColumn column = grid.getColumn(propertyId); column.setVisible(!column.isVisible()); } @@ -403,6 +399,7 @@ public class GridBasicFeatures extends AbstractComponentTest { grid.getContainerDatasource() .removeContainerProperty( getColumnProperty((Integer) data)); + removeCategory("Column " + data); } }, null, c); @@ -421,10 +418,7 @@ public class GridBasicFeatures extends AbstractComponentTest { @Override public void execute(Grid grid, Boolean value, Object columnIndex) { - Object propertyId = (new ArrayList(grid - .getContainerDatasource() - .getContainerPropertyIds()) - .get((Integer) columnIndex)); + Object propertyId = getColumnProperty((Integer) columnIndex); GridColumn column = grid.getColumn(propertyId); column.setSortable(value); } @@ -438,10 +432,7 @@ public class GridBasicFeatures extends AbstractComponentTest { @Override public void execute(Grid grid, Integer value, Object columnIndex) { - Object propertyId = (new ArrayList(grid - .getContainerDatasource() - .getContainerPropertyIds()) - .get((Integer) columnIndex)); + Object propertyId = getColumnProperty((Integer) columnIndex); GridColumn column = grid.getColumn(propertyId); column.setWidthUndefined(); } @@ -454,10 +445,7 @@ public class GridBasicFeatures extends AbstractComponentTest { @Override public void execute(Grid grid, Integer value, Object columnIndex) { - Object propertyId = (new ArrayList(grid - .getContainerDatasource() - .getContainerPropertyIds()) - .get((Integer) columnIndex)); + Object propertyId = getColumnProperty((Integer) columnIndex); GridColumn column = grid.getColumn(propertyId); column.setWidth(value); } @@ -475,10 +463,7 @@ public class GridBasicFeatures extends AbstractComponentTest { @Override public void execute(Grid grid, GridStaticCellType value, Object columnIndex) { - final Object propertyId = (new ArrayList(grid - .getContainerDatasource() - .getContainerPropertyIds()) - .get((Integer) columnIndex)); + final Object propertyId = getColumnProperty((Integer) columnIndex); final HeaderCell cell = grid.getHeader() .getDefaultRow().getCell(propertyId); switch (value) { @@ -516,10 +501,7 @@ public class GridBasicFeatures extends AbstractComponentTest { @Override public void execute(Grid grid, GridStaticCellType value, Object columnIndex) { - final Object propertyId = (new ArrayList(grid - .getContainerDatasource() - .getContainerPropertyIds()) - .get((Integer) columnIndex)); + final Object propertyId = getColumnProperty((Integer) columnIndex); final FooterCell cell = grid.getFooter().getRow(0) .getCell(propertyId); switch (value) { -- cgit v1.2.3 From 1de6a75497bae315dfcb70c272225a6d3ea0af19 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Wed, 27 Aug 2014 15:18:30 +0300 Subject: ScrollbarBundle, Escalator and Grid fire Scroll events (#13334) Change-Id: I362f1f8d2107d762b43ab52c1f22dfd218f67ba4 --- .../src/com/vaadin/client/ui/grid/Escalator.java | 22 ++++++++ client/src/com/vaadin/client/ui/grid/Grid.java | 61 ++++++++++++++++------ .../com/vaadin/client/ui/grid/ScrollbarBundle.java | 55 +++++++++++++++++++ .../grid/events/AbstractGridKeyEventHandler.java | 44 ++++++++++++++++ .../client/ui/grid/events/BodyKeyDownHandler.java | 28 ++++++++++ .../client/ui/grid/events/BodyKeyPressHandler.java | 28 ++++++++++ .../client/ui/grid/events/BodyKeyUpHandler.java | 28 ++++++++++ .../ui/grid/events/FooterKeyDownHandler.java | 28 ++++++++++ .../ui/grid/events/FooterKeyPressHandler.java | 28 ++++++++++ .../client/ui/grid/events/FooterKeyUpHandler.java | 28 ++++++++++ .../client/ui/grid/events/GridKeyDownEvent.java | 50 ++++++++++++++++++ .../client/ui/grid/events/GridKeyPressEvent.java | 51 ++++++++++++++++++ .../client/ui/grid/events/GridKeyUpEvent.java | 50 ++++++++++++++++++ .../ui/grid/events/HeaderKeyDownHandler.java | 28 ++++++++++ .../ui/grid/events/HeaderKeyPressHandler.java | 28 ++++++++++ .../client/ui/grid/events/HeaderKeyUpHandler.java | 28 ++++++++++ .../vaadin/client/ui/grid/events/ScrollEvent.java | 39 ++++++++++++++ .../client/ui/grid/events/ScrollHandler.java | 34 ++++++++++++ .../keyevents/AbstractGridKeyEventHandler.java | 44 ---------------- .../ui/grid/keyevents/BodyKeyDownHandler.java | 28 ---------- .../ui/grid/keyevents/BodyKeyPressHandler.java | 28 ---------- .../client/ui/grid/keyevents/BodyKeyUpHandler.java | 28 ---------- .../ui/grid/keyevents/FooterKeyDownHandler.java | 28 ---------- .../ui/grid/keyevents/FooterKeyPressHandler.java | 28 ---------- .../ui/grid/keyevents/FooterKeyUpHandler.java | 28 ---------- .../client/ui/grid/keyevents/GridKeyDownEvent.java | 50 ------------------ .../ui/grid/keyevents/GridKeyPressEvent.java | 51 ------------------ .../client/ui/grid/keyevents/GridKeyUpEvent.java | 50 ------------------ .../ui/grid/keyevents/HeaderKeyDownHandler.java | 28 ---------- .../ui/grid/keyevents/HeaderKeyPressHandler.java | 28 ---------- .../ui/grid/keyevents/HeaderKeyUpHandler.java | 28 ---------- .../ui/grid/selection/MultiSelectionRenderer.java | 8 +-- .../client/grid/GridBasicClientFeaturesWidget.java | 55 ++++++++++++++----- 33 files changed, 689 insertions(+), 479 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/events/AbstractGridKeyEventHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/BodyKeyDownHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/BodyKeyPressHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/BodyKeyUpHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/FooterKeyDownHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/FooterKeyPressHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/FooterKeyUpHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/GridKeyDownEvent.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/GridKeyPressEvent.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/GridKeyUpEvent.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/HeaderKeyDownHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/HeaderKeyPressHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/HeaderKeyUpHandler.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/ScrollEvent.java create mode 100644 client/src/com/vaadin/client/ui/grid/events/ScrollHandler.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java delete mode 100644 client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index dd220b2964..ceff55e303 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -57,6 +57,8 @@ import com.vaadin.client.ui.grid.PositionFunction.TranslatePosition; import com.vaadin.client.ui.grid.PositionFunction.WebkitTranslate3DPosition; import com.vaadin.client.ui.grid.ScrollbarBundle.HorizontalScrollbarBundle; import com.vaadin.client.ui.grid.ScrollbarBundle.VerticalScrollbarBundle; +import com.vaadin.client.ui.grid.events.ScrollEvent; +import com.vaadin.client.ui.grid.events.ScrollHandler; import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.Range; @@ -3950,11 +3952,20 @@ public class Escalator extends Widget { final Element root = DOM.createDiv(); setElement(root); + ScrollHandler scrollHandler = new ScrollHandler() { + @Override + public void onScroll(ScrollEvent event) { + fireEvent(new ScrollEvent()); + } + }; + root.appendChild(verticalScrollbar.getElement()); + verticalScrollbar.addScrollHandler(scrollHandler); verticalScrollbar.getElement().setTabIndex(-1); verticalScrollbar.setScrollbarThickness(Util.getNativeScrollbarSize()); root.appendChild(horizontalScrollbar.getElement()); + horizontalScrollbar.addScrollHandler(scrollHandler); horizontalScrollbar.getElement().setTabIndex(-1); horizontalScrollbar .setScrollbarThickness(Util.getNativeScrollbarSize()); @@ -4668,4 +4679,15 @@ public class Escalator extends Widget { + direction); } } + + /** + * Adds a scroll handler to this escalator + * + * @param handler + * the scroll handler to add + * @return a handler registration for the registered scroll handler + */ + public HandlerRegistration addScrollHandler(ScrollHandler handler) { + return addHandler(handler, ScrollEvent.TYPE); + } } diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 4d8aa25c3b..9c12b37bb5 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -52,22 +52,24 @@ import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.grid.GridFooter.FooterRow; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler; -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDownHandler; -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPressHandler; -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUpHandler; -import com.vaadin.client.ui.grid.keyevents.BodyKeyDownHandler; -import com.vaadin.client.ui.grid.keyevents.BodyKeyPressHandler; -import com.vaadin.client.ui.grid.keyevents.BodyKeyUpHandler; -import com.vaadin.client.ui.grid.keyevents.FooterKeyDownHandler; -import com.vaadin.client.ui.grid.keyevents.FooterKeyPressHandler; -import com.vaadin.client.ui.grid.keyevents.FooterKeyUpHandler; -import com.vaadin.client.ui.grid.keyevents.GridKeyDownEvent; -import com.vaadin.client.ui.grid.keyevents.GridKeyPressEvent; -import com.vaadin.client.ui.grid.keyevents.GridKeyUpEvent; -import com.vaadin.client.ui.grid.keyevents.HeaderKeyDownHandler; -import com.vaadin.client.ui.grid.keyevents.HeaderKeyPressHandler; -import com.vaadin.client.ui.grid.keyevents.HeaderKeyUpHandler; +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler; +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyDownHandler; +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyPressHandler; +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyUpHandler; +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.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.WidgetRenderer; import com.vaadin.client.ui.grid.selection.HasSelectionChangeHandlers; @@ -1225,6 +1227,13 @@ public class Grid extends Composite implements setSelectionMode(SelectionMode.SINGLE); + escalator.addScrollHandler(new ScrollHandler() { + @Override + public void onScroll(ScrollEvent event) { + fireEvent(new ScrollEvent()); + } + }); + escalator .addRowVisibilityChangeHandler(new RowVisibilityChangeHandler() { @Override @@ -1814,6 +1823,15 @@ public class Grid extends Composite implements return escalator.getScrollTop(); } + /** + * Gets the horizontal scroll offset + * + * @return the number of pixels this grid is scrolled to the right + */ + public double getScrollLeft() { + return escalator.getScrollLeft(); + } + private static final Logger getLogger() { return Logger.getLogger(Grid.class.getName()); } @@ -2560,4 +2578,15 @@ public class Grid extends Composite implements return firstRowIndex; } + + /** + * Adds a scroll handler to this grid + * + * @param handler + * the scroll handler to add + * @return a handler registration for the registered scroll handler + */ + public HandlerRegistration addScrollHandler(ScrollHandler handler) { + return addHandler(handler, ScrollEvent.TYPE); + } } diff --git a/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java b/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java index a45affb0be..ceaa4b9fec 100644 --- a/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java +++ b/client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java @@ -16,6 +16,8 @@ package com.vaadin.client.ui.grid; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.dom.client.Style.Unit; @@ -27,6 +29,8 @@ import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.EventListener; import com.google.gwt.user.client.Timer; +import com.vaadin.client.ui.grid.events.ScrollEvent; +import com.vaadin.client.ui.grid.events.ScrollHandler; /** * An element-like bundle representing a configurable and visual scrollbar in @@ -39,6 +43,41 @@ import com.google.gwt.user.client.Timer; */ abstract class ScrollbarBundle { + private class ScrollEventFirer { + private final ScheduledCommand fireEventCommand = new ScheduledCommand() { + @Override + public void execute() { + if (!pixelValuesEqual(startScrollPos, getScrollPos())) { + getHandlerManager().fireEvent(new ScrollEvent()); + } + reset(); + } + }; + + private boolean isBeingFired; + private double startScrollPos; + + public ScrollEventFirer() { + reset(); + } + + public void scheduleEvent() { + if (!isBeingFired) { + /* + * We'll gather all the scroll events, and only fire once, once + * everything has calmed down. + */ + Scheduler.get().scheduleDeferred(fireEventCommand); + isBeingFired = true; + } + } + + private void reset() { + isBeingFired = false; + startScrollPos = getScrollPos(); + } + } + /** * The orientation of the scrollbar. */ @@ -288,6 +327,8 @@ abstract class ScrollbarBundle { private TemporaryResizer invisibleScrollbarTemporaryResizer = new TemporaryResizer(); + private final ScrollEventFirer scrollEventFirer = new ScrollEventFirer(); + private ScrollbarBundle() { root.appendChild(scrollSizeElement); } @@ -409,6 +450,8 @@ abstract class ScrollbarBundle { * only facilitating future virtual scrollbars. */ internalSetScrollPos(toInt32(scrollPos)); + + scrollEventFirer.scheduleEvent(); } } @@ -603,6 +646,7 @@ abstract class ScrollbarBundle { int newScrollPos = internalGetScrollPos(); if (!isLocked()) { scrollPos = newScrollPos; + scrollEventFirer.scheduleEvent(); } else if (scrollPos != newScrollPos) { // we need to actually undo the setting of the scroll. internalSetScrollPos(toInt32(scrollPos)); @@ -694,4 +738,15 @@ abstract class ScrollbarBundle { * @return the scroll direction of this scrollbar bundle */ public abstract Direction getDirection(); + + /** + * Adds a scroll handler to the scrollbar bundle. + * + * @param handler + * the handler to add + * @return the registration object for the handler registration + */ + public HandlerRegistration addScrollHandler(final ScrollHandler handler) { + return getHandlerManager().addHandler(ScrollEvent.TYPE, handler); + } } diff --git a/client/src/com/vaadin/client/ui/grid/events/AbstractGridKeyEventHandler.java b/client/src/com/vaadin/client/ui/grid/events/AbstractGridKeyEventHandler.java new file mode 100644 index 0000000000..8dcd24305b --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/AbstractGridKeyEventHandler.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.google.gwt.event.shared.EventHandler; +import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; + +/** + * Base interface of all handlers for {@link AbstractGridKeyEvent}s. + * + * @since + * @author Vaadin Ltd + */ +public abstract interface AbstractGridKeyEventHandler extends EventHandler { + + public abstract interface GridKeyDownHandler extends + AbstractGridKeyEventHandler { + public void onKeyDown(GridKeyDownEvent event); + } + + public abstract interface GridKeyUpHandler extends + AbstractGridKeyEventHandler { + public void onKeyUp(GridKeyUpEvent event); + } + + public abstract interface GridKeyPressHandler extends + AbstractGridKeyEventHandler { + public void onKeyPress(GridKeyPressEvent event); + } + +} diff --git a/client/src/com/vaadin/client/ui/grid/events/BodyKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/events/BodyKeyDownHandler.java new file mode 100644 index 0000000000..2ec81174b9 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/BodyKeyDownHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyDownHandler; + +/** + * Handler for {@link GridKeyDownEvent}s that happen when active cell is in the + * body of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface BodyKeyDownHandler extends GridKeyDownHandler { +} diff --git a/client/src/com/vaadin/client/ui/grid/events/BodyKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/events/BodyKeyPressHandler.java new file mode 100644 index 0000000000..f328a11ab8 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/BodyKeyPressHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyPressHandler; + +/** + * Handler for {@link GridKeyPressEvent}s that happen when active cell is in the + * body of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface BodyKeyPressHandler extends GridKeyPressHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/events/BodyKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/events/BodyKeyUpHandler.java new file mode 100644 index 0000000000..f5cab67946 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/BodyKeyUpHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyUpHandler; + +/** + * Handler for {@link GridKeyUpEvent}s that happen when active cell is in the + * body of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface BodyKeyUpHandler extends GridKeyUpHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/events/FooterKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/events/FooterKeyDownHandler.java new file mode 100644 index 0000000000..e84da350dd --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/FooterKeyDownHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyDownHandler; + +/** + * Handler for {@link GridKeyDownEvent}s that happen when active cell is in the + * footer of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface FooterKeyDownHandler extends GridKeyDownHandler { +} diff --git a/client/src/com/vaadin/client/ui/grid/events/FooterKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/events/FooterKeyPressHandler.java new file mode 100644 index 0000000000..617e25f190 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/FooterKeyPressHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyPressHandler; + +/** + * Handler for {@link GridKeyPressEvent}s that happen when active cell is in the + * footer of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface FooterKeyPressHandler extends GridKeyPressHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/events/FooterKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/events/FooterKeyUpHandler.java new file mode 100644 index 0000000000..4dd3dc7f01 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/FooterKeyUpHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyUpHandler; + +/** + * Handler for {@link GridKeyUpEvent}s that happen when active cell is in the + * footer of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface FooterKeyUpHandler extends GridKeyUpHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/events/GridKeyDownEvent.java b/client/src/com/vaadin/client/ui/grid/events/GridKeyDownEvent.java new file mode 100644 index 0000000000..2fab683bb0 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/GridKeyDownEvent.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.google.gwt.dom.client.BrowserEvents; +import com.vaadin.client.ui.grid.Grid; +import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyDownHandler; + +/** + * Represents native key down event in Grid. + * + * @since + * @author Vaadin Ltd + */ +public class GridKeyDownEvent extends AbstractGridKeyEvent { + + public GridKeyDownEvent(Grid grid) { + super(grid); + } + + @Override + protected void dispatch(GridKeyDownHandler handler) { + super.dispatch(handler); + if ((activeSection == GridSection.BODY && handler instanceof BodyKeyDownHandler) + || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyDownHandler) + || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyDownHandler)) { + handler.onKeyDown(this); + } + } + + @Override + protected String getBrowserEventType() { + return BrowserEvents.KEYDOWN; + } + +} diff --git a/client/src/com/vaadin/client/ui/grid/events/GridKeyPressEvent.java b/client/src/com/vaadin/client/ui/grid/events/GridKeyPressEvent.java new file mode 100644 index 0000000000..112200b03a --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/GridKeyPressEvent.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.google.gwt.dom.client.BrowserEvents; +import com.vaadin.client.ui.grid.Grid; +import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyPressHandler; + +/** + * Represents native key press event in Grid. + * + * @since + * @author Vaadin Ltd + */ +public class GridKeyPressEvent extends + AbstractGridKeyEvent { + + public GridKeyPressEvent(Grid grid) { + super(grid); + } + + @Override + protected void dispatch(GridKeyPressHandler handler) { + super.dispatch(handler); + if ((activeSection == GridSection.BODY && handler instanceof BodyKeyPressHandler) + || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyPressHandler) + || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyPressHandler)) { + handler.onKeyPress(this); + } + } + + @Override + protected String getBrowserEventType() { + return BrowserEvents.KEYPRESS; + } + +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/events/GridKeyUpEvent.java b/client/src/com/vaadin/client/ui/grid/events/GridKeyUpEvent.java new file mode 100644 index 0000000000..9aa8ce7084 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/GridKeyUpEvent.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.google.gwt.dom.client.BrowserEvents; +import com.vaadin.client.ui.grid.Grid; +import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyUpHandler; + +/** + * Represents native key up event in Grid. + * + * @since + * @author Vaadin Ltd + */ +public class GridKeyUpEvent extends AbstractGridKeyEvent { + + public GridKeyUpEvent(Grid grid) { + super(grid); + } + + @Override + protected void dispatch(GridKeyUpHandler handler) { + super.dispatch(handler); + if ((activeSection == GridSection.BODY && handler instanceof BodyKeyUpHandler) + || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyUpHandler) + || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyUpHandler)) { + handler.onKeyUp(this); + } + } + + @Override + protected String getBrowserEventType() { + return BrowserEvents.KEYUP; + } + +} diff --git a/client/src/com/vaadin/client/ui/grid/events/HeaderKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/events/HeaderKeyDownHandler.java new file mode 100644 index 0000000000..a19bfad6bf --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/HeaderKeyDownHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyDownHandler; + +/** + * Handler for {@link GridKeyDownEvent}s that happen when active cell is in the + * header of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface HeaderKeyDownHandler extends GridKeyDownHandler { +} diff --git a/client/src/com/vaadin/client/ui/grid/events/HeaderKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/events/HeaderKeyPressHandler.java new file mode 100644 index 0000000000..1188dc9b3e --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/HeaderKeyPressHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyPressHandler; + +/** + * Handler for {@link GridKeyPressEvent}s that happen when active cell is in the + * header of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface HeaderKeyPressHandler extends GridKeyPressHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/events/HeaderKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/events/HeaderKeyUpHandler.java new file mode 100644 index 0000000000..3a8bc3e78a --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/HeaderKeyUpHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyUpHandler; + +/** + * Handler for {@link GridKeyUpEvent}s that happen when active cell is in the + * header of the Grid. + * + * @since + * @author Vaadin Ltd + */ +public interface HeaderKeyUpHandler extends GridKeyUpHandler { +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/events/ScrollEvent.java b/client/src/com/vaadin/client/ui/grid/events/ScrollEvent.java new file mode 100644 index 0000000000..751823f9a5 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/ScrollEvent.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.google.gwt.event.shared.GwtEvent; + +/** + * An event that signifies that a scrollbar bundle has been scrolled + * + * @author Vaadin Ltd + */ +public class ScrollEvent extends GwtEvent { + + /** The type of this event */ + public static final Type TYPE = new Type(); + + @Override + public Type getAssociatedType() { + return TYPE; + } + + @Override + protected void dispatch(final ScrollHandler handler) { + handler.onScroll(this); + } +} diff --git a/client/src/com/vaadin/client/ui/grid/events/ScrollHandler.java b/client/src/com/vaadin/client/ui/grid/events/ScrollHandler.java new file mode 100644 index 0000000000..473b18071a --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/ScrollHandler.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid.events; + +import com.google.gwt.event.shared.EventHandler; + +/** + * A handler that gets called whenever a scrollbar bundle is scrolled + * + * @author Vaadin Ltd + */ +public interface ScrollHandler extends EventHandler { + /** + * A callback method that is called once a scrollbar bundle has been + * scrolled. + * + * @param event + * the scroll event + */ + public void onScroll(ScrollEvent event); +} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java deleted file mode 100644 index 57708e8bc9..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/AbstractGridKeyEventHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.google.gwt.event.shared.EventHandler; -import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; - -/** - * Base interface of all handlers for {@link AbstractGridKeyEvent}s. - * - * @since - * @author Vaadin Ltd - */ -public abstract interface AbstractGridKeyEventHandler extends EventHandler { - - public abstract interface GridKeyDownHandler extends - AbstractGridKeyEventHandler { - public void onKeyDown(GridKeyDownEvent event); - } - - public abstract interface GridKeyUpHandler extends - AbstractGridKeyEventHandler { - public void onKeyUp(GridKeyUpEvent event); - } - - public abstract interface GridKeyPressHandler extends - AbstractGridKeyEventHandler { - public void onKeyPress(GridKeyPressEvent event); - } - -} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java deleted file mode 100644 index 9e61624a28..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyDownHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDownHandler; - -/** - * Handler for {@link GridKeyDownEvent}s that happen when active cell is in the - * body of the Grid. - * - * @since - * @author Vaadin Ltd - */ -public interface BodyKeyDownHandler extends GridKeyDownHandler { -} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java deleted file mode 100644 index f44c1d172e..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyPressHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPressHandler; - -/** - * Handler for {@link GridKeyPressEvent}s that happen when active cell is in the - * body of the Grid. - * - * @since - * @author Vaadin Ltd - */ -public interface BodyKeyPressHandler extends GridKeyPressHandler { -} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java deleted file mode 100644 index a6b3929d80..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/BodyKeyUpHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUpHandler; - -/** - * Handler for {@link GridKeyUpEvent}s that happen when active cell is in the - * body of the Grid. - * - * @since - * @author Vaadin Ltd - */ -public interface BodyKeyUpHandler extends GridKeyUpHandler { -} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java deleted file mode 100644 index 5e9fffdcda..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyDownHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDownHandler; - -/** - * Handler for {@link GridKeyDownEvent}s that happen when active cell is in the - * footer of the Grid. - * - * @since - * @author Vaadin Ltd - */ -public interface FooterKeyDownHandler extends GridKeyDownHandler { -} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java deleted file mode 100644 index d5713d9135..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyPressHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPressHandler; - -/** - * Handler for {@link GridKeyPressEvent}s that happen when active cell is in the - * footer of the Grid. - * - * @since - * @author Vaadin Ltd - */ -public interface FooterKeyPressHandler extends GridKeyPressHandler { -} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java deleted file mode 100644 index 87978e1cd2..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/FooterKeyUpHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUpHandler; - -/** - * Handler for {@link GridKeyUpEvent}s that happen when active cell is in the - * footer of the Grid. - * - * @since - * @author Vaadin Ltd - */ -public interface FooterKeyUpHandler extends GridKeyUpHandler { -} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java deleted file mode 100644 index 65c8327eb6..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyDownEvent.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.google.gwt.dom.client.BrowserEvents; -import com.vaadin.client.ui.grid.Grid; -import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDownHandler; - -/** - * Represents native key down event in Grid. - * - * @since - * @author Vaadin Ltd - */ -public class GridKeyDownEvent extends AbstractGridKeyEvent { - - public GridKeyDownEvent(Grid grid) { - super(grid); - } - - @Override - protected void dispatch(GridKeyDownHandler handler) { - super.dispatch(handler); - if ((activeSection == GridSection.BODY && handler instanceof BodyKeyDownHandler) - || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyDownHandler) - || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyDownHandler)) { - handler.onKeyDown(this); - } - } - - @Override - protected String getBrowserEventType() { - return BrowserEvents.KEYDOWN; - } - -} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java deleted file mode 100644 index 388467990b..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyPressEvent.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.google.gwt.dom.client.BrowserEvents; -import com.vaadin.client.ui.grid.Grid; -import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPressHandler; - -/** - * Represents native key press event in Grid. - * - * @since - * @author Vaadin Ltd - */ -public class GridKeyPressEvent extends - AbstractGridKeyEvent { - - public GridKeyPressEvent(Grid grid) { - super(grid); - } - - @Override - protected void dispatch(GridKeyPressHandler handler) { - super.dispatch(handler); - if ((activeSection == GridSection.BODY && handler instanceof BodyKeyPressHandler) - || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyPressHandler) - || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyPressHandler)) { - handler.onKeyPress(this); - } - } - - @Override - protected String getBrowserEventType() { - return BrowserEvents.KEYPRESS; - } - -} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java b/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java deleted file mode 100644 index dd1fb33e3f..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/GridKeyUpEvent.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.google.gwt.dom.client.BrowserEvents; -import com.vaadin.client.ui.grid.Grid; -import com.vaadin.client.ui.grid.Grid.AbstractGridKeyEvent; -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUpHandler; - -/** - * Represents native key up event in Grid. - * - * @since - * @author Vaadin Ltd - */ -public class GridKeyUpEvent extends AbstractGridKeyEvent { - - public GridKeyUpEvent(Grid grid) { - super(grid); - } - - @Override - protected void dispatch(GridKeyUpHandler handler) { - super.dispatch(handler); - if ((activeSection == GridSection.BODY && handler instanceof BodyKeyUpHandler) - || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyUpHandler) - || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyUpHandler)) { - handler.onKeyUp(this); - } - } - - @Override - protected String getBrowserEventType() { - return BrowserEvents.KEYUP; - } - -} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java deleted file mode 100644 index d8a1132a84..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyDownHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyDownHandler; - -/** - * Handler for {@link GridKeyDownEvent}s that happen when active cell is in the - * header of the Grid. - * - * @since - * @author Vaadin Ltd - */ -public interface HeaderKeyDownHandler extends GridKeyDownHandler { -} diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java deleted file mode 100644 index a2245b1dfe..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyPressHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyPressHandler; - -/** - * Handler for {@link GridKeyPressEvent}s that happen when active cell is in the - * header of the Grid. - * - * @since - * @author Vaadin Ltd - */ -public interface HeaderKeyPressHandler extends GridKeyPressHandler { -} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java b/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java deleted file mode 100644 index 405195ec94..0000000000 --- a/client/src/com/vaadin/client/ui/grid/keyevents/HeaderKeyUpHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.ui.grid.keyevents; - -import com.vaadin.client.ui.grid.keyevents.AbstractGridKeyEventHandler.GridKeyUpHandler; - -/** - * Handler for {@link GridKeyUpEvent}s that happen when active cell is in the - * header of the Grid. - * - * @since - * @author Vaadin Ltd - */ -public interface HeaderKeyUpHandler extends GridKeyUpHandler { -} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java index bfcc639a64..222c8ab806 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java @@ -41,10 +41,10 @@ import com.vaadin.client.ui.grid.DataAvailableEvent; import com.vaadin.client.ui.grid.DataAvailableHandler; import com.vaadin.client.ui.grid.FlyweightCell; import com.vaadin.client.ui.grid.Grid; -import com.vaadin.client.ui.grid.keyevents.BodyKeyDownHandler; -import com.vaadin.client.ui.grid.keyevents.BodyKeyUpHandler; -import com.vaadin.client.ui.grid.keyevents.GridKeyDownEvent; -import com.vaadin.client.ui.grid.keyevents.GridKeyUpEvent; +import com.vaadin.client.ui.grid.events.BodyKeyDownHandler; +import com.vaadin.client.ui.grid.events.BodyKeyUpHandler; +import com.vaadin.client.ui.grid.events.GridKeyDownEvent; +import com.vaadin.client.ui.grid.events.GridKeyUpEvent; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.selection.SelectionModel.Multi.Batched; import com.vaadin.shared.ui.grid.ScrollDestination; diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index 1bdbd76a20..14388aec6e 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -23,8 +23,10 @@ import java.util.Random; import com.google.gwt.core.client.Scheduler.ScheduledCommand; 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.vaadin.client.ui.VLabel; import com.vaadin.client.ui.grid.Cell; import com.vaadin.client.ui.grid.FlyweightCell; @@ -39,18 +41,20 @@ 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.keyevents.BodyKeyDownHandler; -import com.vaadin.client.ui.grid.keyevents.BodyKeyPressHandler; -import com.vaadin.client.ui.grid.keyevents.BodyKeyUpHandler; -import com.vaadin.client.ui.grid.keyevents.FooterKeyDownHandler; -import com.vaadin.client.ui.grid.keyevents.FooterKeyPressHandler; -import com.vaadin.client.ui.grid.keyevents.FooterKeyUpHandler; -import com.vaadin.client.ui.grid.keyevents.GridKeyDownEvent; -import com.vaadin.client.ui.grid.keyevents.GridKeyPressEvent; -import com.vaadin.client.ui.grid.keyevents.GridKeyUpEvent; -import com.vaadin.client.ui.grid.keyevents.HeaderKeyDownHandler; -import com.vaadin.client.ui.grid.keyevents.HeaderKeyPressHandler; -import com.vaadin.client.ui.grid.keyevents.HeaderKeyUpHandler; +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; @@ -249,6 +253,7 @@ public class GridBasicClientFeaturesWidget extends createColumnsMenu(); createHeaderMenu(); createFooterMenu(); + createInternalsMenu(); grid.getElement().getStyle().setZIndex(0); addNorth(grid, 400); @@ -256,6 +261,32 @@ public class GridBasicClientFeaturesWidget extends 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", -- cgit v1.2.3 From 63735b6f70d41c642f3d043bbba88093e6c2fba7 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 19 Aug 2014 16:23:04 +0300 Subject: Initial client-side editor row implementation (#13334) Only shows a bare grey row for now. Enter opens editor for active row, Esc hides editor. TODO * Double-click to edit does not work * Scrolling to edit hidden row does not work * EditorRowHandler to bind data+widgets * Server-side integration * Commit/discard buttons Change-Id: I0ae678b086493b0e46ab7c1db99eb92049318d6f --- WebContent/VAADIN/themes/base/grid/grid.scss | 12 ++ .../src/com/vaadin/client/ui/grid/EditorRow.java | 207 +++++++++++++++++++++ .../src/com/vaadin/client/ui/grid/Escalator.java | 2 +- client/src/com/vaadin/client/ui/grid/Grid.java | 135 ++++++++++---- .../grid/basicfeatures/GridBasicFeaturesTest.java | 9 + .../basicfeatures/client/GridEditorRowTest.java | 36 ++++ .../client/grid/GridBasicClientFeaturesWidget.java | 21 +++ 7 files changed, 387 insertions(+), 35 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/EditorRow.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java (limited to 'uitest/src') diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index 88c7754a10..de38b8c1ff 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -35,4 +35,16 @@ .#{$primaryStyleName}-row-selected > td { background: lightblue; } + + .#{$primaryStyleName}-editor-row { + + position: absolute; + background: #EEE; + box-shadow: 0 0 5px; + + & > div { + position: absolute; + border: 1px solid #CCC; + } + } } diff --git a/client/src/com/vaadin/client/ui/grid/EditorRow.java b/client/src/com/vaadin/client/ui/grid/EditorRow.java new file mode 100644 index 0000000000..45374962b7 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/EditorRow.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.client.ui.grid; + +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.dom.client.TableCellElement; +import com.google.gwt.dom.client.TableRowElement; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.user.client.DOM; +import com.vaadin.client.ui.grid.Escalator.AbstractRowContainer; +import com.vaadin.shared.ui.grid.ScrollDestination; + +/** + * An editor UI for Grid rows. A single Grid row at a time can be opened for + * editing. + * + * @since + * @author Vaadin Ltd + */ +public class EditorRow { + + public static final int KEYCODE_SHOW = KeyCodes.KEY_ENTER; + public static final int KEYCODE_HIDE = KeyCodes.KEY_ESCAPE; + + public enum State { + INACTIVE, ACTIVATING, ACTIVE, COMMITTING + } + + private DivElement editorOverlay = DivElement.as(DOM.createDiv()); + + private Grid grid; + + private boolean enabled = false; + private State state = State.INACTIVE; + private int rowIndex = -1; + private String styleName = null; + + public int getRow() { + return rowIndex; + } + + /** + * Opens the editor over the row with the given index. + * + * @param rowIndex + * the index of the row to be edited + * + * @throws IllegalStateException + * if this editor row is not enabled or if it is already in edit + * mode + */ + public void editRow(int rowIndex) { + if (!enabled) { + throw new IllegalStateException( + "Cannot edit row: EditorRow is not enabled"); + } + if (state != State.INACTIVE) { + throw new IllegalStateException( + "Cannot edit row: EditorRow already in edit mode"); + } + + this.rowIndex = rowIndex; + + state = State.ACTIVATING; + + boolean rowVisible = grid.getEscalator().getVisibleRowRange() + .contains(rowIndex); + + if (!rowVisible) { + grid.scrollToRow(rowIndex, ScrollDestination.MIDDLE); + } else { + grid.getEscalator().getBody().refreshRows(rowIndex, 1); + } + } + + /** + * Cancels the currently active edit and hides the editor. + * + * @throws IllegalStateException + * if this editor row is not in edit mode + */ + public void cancel() { + if (state == State.INACTIVE) { + throw new IllegalStateException( + "Cannot cancel edit: EditorRow is not in edit mode"); + } + state = State.INACTIVE; + hideOverlay(); + + grid.getEscalator().getBody().refreshRows(rowIndex, 1); + } + + public boolean isEnabled() { + return enabled; + } + + /** + * Sets the enabled state of this editor row. + * + * @param enabled + * true if enabled, false otherwise + * + * @throws IllegalStateException + * if in edit mode and trying to disable + */ + public void setEnabled(boolean enabled) { + if (enabled == false && state != State.INACTIVE) { + throw new IllegalStateException( + "Cannot disable: EditorRow is in edit mode"); + } + this.enabled = enabled; + } + + protected void setGrid(Grid grid) { + this.grid = grid; + } + + protected State getState() { + return state; + } + + protected void setState(State state) { + this.state = state; + } + + /** + * Opens the editor overlay over the given table row. + * + * @param tr + * the row to be edited + */ + protected void showOverlay(TableRowElement tr) { + + DivElement tableWrapper = DivElement.as(tr.getParentElement() + .getParentElement().getParentElement()); + + AbstractRowContainer body = (AbstractRowContainer) grid.getEscalator() + .getBody(); + + int rowTop = body.getRowTop(tr); + int bodyTop = body.getElement().getAbsoluteTop(); + int wrapperTop = tableWrapper.getAbsoluteTop(); + + setBounds(editorOverlay, tr.getOffsetLeft(), rowTop + bodyTop + - wrapperTop, tr.getOffsetWidth(), tr.getOffsetHeight()); + + for (int i = 0; i < tr.getCells().getLength(); i++) { + Element cell = createCell(tr.getCells().getItem(i)); + editorOverlay.appendChild(cell); + } + + tableWrapper.appendChild(editorOverlay); + } + + protected void hideOverlay() { + editorOverlay.removeFromParent(); + } + + protected void setStylePrimaryName(String primaryName) { + if (styleName != null) { + editorOverlay.removeClassName(styleName); + } + styleName = primaryName + "-editor-row"; + editorOverlay.addClassName(styleName); + } + + /** + * Creates an editor row cell corresponding to the given table cell. The + * returned element is empty and has the same dimensions and position as the + * table cell. + * + * @param td + * the table cell used as a reference + * @return an editor row cell corresponding to the given cell + */ + protected Element createCell(TableCellElement td) { + DivElement cell = DivElement.as(DOM.createDiv()); + setBounds(cell, td.getOffsetLeft(), td.getOffsetTop(), + td.getOffsetWidth(), td.getOffsetHeight()); + return cell; + } + + private static void setBounds(Element e, int left, int top, int width, + int height) { + Style style = e.getStyle(); + style.setLeft(left, Unit.PX); + style.setTop(top, Unit.PX); + style.setWidth(width, Unit.PX); + style.setHeight(height, Unit.PX); + } +} diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java index ceff55e303..f686ec03ca 100644 --- a/client/src/com/vaadin/client/ui/grid/Escalator.java +++ b/client/src/com/vaadin/client/ui/grid/Escalator.java @@ -1058,7 +1058,7 @@ public class Escalator extends Widget { } } - private abstract class AbstractRowContainer implements RowContainer { + protected abstract class AbstractRowContainer implements RowContainer { private EscalatorUpdater updater = EscalatorUpdater.NULL; diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 9c12b37bb5..89bf7fbc2b 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -49,6 +49,7 @@ import com.vaadin.client.Util; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.SubPartAware; +import com.vaadin.client.ui.grid.EditorRow.State; import com.vaadin.client.ui.grid.GridFooter.FooterRow; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; @@ -665,6 +666,8 @@ public class Grid extends Composite implements private final LazySorter lazySorter = new LazySorter(); + private final EditorRow editorRow = GWT.create(EditorRow.class); + /** * Enumeration for easy setting of selection mode. */ @@ -937,7 +940,7 @@ public class Grid extends Composite implements @Override public void update(Row row, Iterable cellsToUpdate) { int rowIndex = row.getRow(); - Element rowElement = row.getElement(); + TableRowElement rowElement = row.getElement(); T rowData = dataSource.getRow(rowIndex); boolean hasData = rowData != null; @@ -972,8 +975,8 @@ public class Grid extends Composite implements Renderer renderer = column.getRenderer(); - // Hide cell content if needed if (renderer instanceof ComplexRenderer) { + // Hide cell content if needed ComplexRenderer clxRenderer = (ComplexRenderer) renderer; if (hasData) { if (!usedToHaveData) { @@ -999,6 +1002,13 @@ public class Grid extends Composite implements cell.getElement().removeAllChildren(); } } + + if (rowIndex == editorRow.getRow()) { + if (editorRow.getState() == State.ACTIVATING) { + editorRow.setState(State.ACTIVE); + editorRow.showOverlay(rowElement); + } + } } @Override @@ -1225,6 +1235,8 @@ public class Grid extends Composite implements footer.setGrid(this); + editorRow.setGrid(this); + setSelectionMode(SelectionMode.SINGLE); escalator.addScrollHandler(new ScrollHandler() { @@ -1267,6 +1279,8 @@ public class Grid extends Composite implements public void setStylePrimaryName(String style) { super.setStylePrimaryName(style); escalator.setStylePrimaryName(style); + editorRow.setStylePrimaryName(style); + rowHasDataStyleName = getStylePrimaryName() + "-row-has-data"; rowSelectedStyleName = getStylePrimaryName() + "-row-selected"; cellActiveStyleName = getStylePrimaryName() + "-cell-active"; @@ -1582,6 +1596,14 @@ public class Grid extends Composite implements return footer; } + public EditorRow getEditorRow() { + return editorRow; + } + + protected Escalator getEscalator() { + return escalator; + } + /** * {@inheritDoc} *

@@ -1930,45 +1952,90 @@ public class Grid extends Composite implements @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); + EventTarget target = event.getEventTarget(); - if (Element.is(target)) { - Element e = Element.as(target); - RowContainer container = escalator.findRowContainer(e); - Cell cell = null; - if (container != null) { - cell = container.getCell(e); - if (cell != null) { - // FIXME getFromVisibleIndex??? - GridColumn gridColumn = columns.get(cell.getColumn()); - - if (container == escalator.getHeader()) { - if (getHeader().getRow(cell.getRow()).isDefault()) { - handleDefaultRowEvent(cell, event); - } - } else if (container == escalator.getFooter()) { - // NOP - } else if (gridColumn.getRenderer() instanceof ComplexRenderer) { - ComplexRenderer cplxRenderer = (ComplexRenderer) gridColumn - .getRenderer(); - if (cplxRenderer.getConsumedEvents().contains( - event.getType())) { - if (cplxRenderer.onBrowserEvent(cell, event)) { - return; - } - } - } + + if (!Element.is(target)) { + return; + } + + Element e = Element.as(target); + RowContainer container = escalator.findRowContainer(e); + Cell cell = container != null ? container.getCell(e) : null; + + if (doEditorRowEvent(event, container, cell)) { + return; + } + + if (container == escalator.getHeader()) { + if (getHeader().getRow(cell.getRow()).isDefault()) { + handleDefaultRowEvent(cell, event); + } + } + + if (doRendererEvent(event, container, cell)) { + return; + } + + if (doActiveCellEvent(event, container, cell)) { + return; + } + } + + private boolean doEditorRowEvent(Event event, RowContainer container, + Cell cell) { + if (editorRow.getState() != State.INACTIVE) { + if (event.getTypeInt() == Event.ONKEYDOWN + && event.getKeyCode() == EditorRow.KEYCODE_HIDE) { + editorRow.cancel(); + } + return true; + } + if (editorRow.isEnabled()) { + if (event.getTypeInt() == Event.ONDBLCLICK) { + if (container == escalator.getBody() && cell != null) { + editorRow.editRow(cell.getRow()); + return true; } + } else if (event.getTypeInt() == Event.ONKEYDOWN + && event.getKeyCode() == EditorRow.KEYCODE_SHOW) { + editorRow.editRow(activeCellHandler.activeRow); + return true; } + } + return false; + } + + private boolean doRendererEvent(Event event, RowContainer container, + Cell cell) { + + if (container == escalator.getBody() && cell != null) { + GridColumn gridColumn = getColumnFromVisibleIndex(cell + .getColumn()); - Collection navigation = activeCellHandler - .getNavigationEvents(); - if (navigation.contains(event.getType()) - && (Util.getFocusedElement() == getElement() || cell != null)) { - activeCellHandler.handleNavigationEvent(event, cell); + if (gridColumn.getRenderer() instanceof ComplexRenderer) { + ComplexRenderer cplxRenderer = (ComplexRenderer) gridColumn + .getRenderer(); + if (cplxRenderer.getConsumedEvents().contains(event.getType())) { + if (cplxRenderer.onBrowserEvent(cell, event)) { + return true; + } + } } + } + return false; + } - handleGridNavigation(event, cell); + private boolean doActiveCellEvent(Event event, RowContainer container, + Cell cell) { + Collection navigation = activeCellHandler.getNavigationEvents(); + if (navigation.contains(event.getType()) + && (Util.getFocusedElement() == getElement() || cell != null)) { + activeCellHandler.handleNavigationEvent(event, cell); } + handleGridNavigation(event, cell); + + return false; } private void handleGridNavigation(Event event, Cell cell) { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java index 6ef0ab5006..8952b04d02 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java @@ -90,6 +90,15 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { return footerCells; } + protected WebElement getEditorRow() { + List 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) { 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..d285bf5c6c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.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.client; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest; + +public class GridEditorRowTest extends GridBasicClientFeaturesTest { + + @Test + public void testEditorRowOpening() throws Exception { + openTestURL(); + + selectMenuPath("Component", "State", "Editor row", "Enabled"); + + selectMenuPath("Component", "State", "Editor row", "Edit row 5"); + + assertNotNull(getEditorRow()); + } +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index 14388aec6e..88d406c0f8 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -337,6 +337,27 @@ public class GridBasicClientFeaturesWidget extends } }, primaryStyleNamePath); + addMenuCommand("Enabled", new ScheduledCommand() { + @Override + public void execute() { + grid.getEditorRow() + .setEnabled(!grid.getEditorRow().isEnabled()); + } + }, "Component", "State", "Editor row"); + + addMenuCommand("Edit row 5", new ScheduledCommand() { + @Override + public void execute() { + grid.getEditorRow().editRow(5); + } + }, "Component", "State", "Editor row"); + + addMenuCommand("Edit row 100", new ScheduledCommand() { + @Override + public void execute() { + grid.getEditorRow().editRow(100); + } + }, "Component", "State", "Editor row"); } private void createColumnsMenu() { -- cgit v1.2.3 From 2aba81c12d0b11d8618fb11142d7c74559647426 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Tue, 26 Aug 2014 15:58:37 +0300 Subject: Tests vScroll behavior in row-amount border cases (#13334) Change-Id: I1a14e9721549b50ddda0aec0ed2cbbabe6f1abd6 --- .../grid/basicfeatures/GridBasicFeatures.java | 54 +++++++++++++--------- .../grid/basicfeatures/GridBasicFeaturesTest.java | 2 +- .../basicfeatures/server/GridStructureTest.java | 23 +++++++++ 3 files changed, 55 insertions(+), 24 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 87109b5007..b760f8531c 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -537,36 +537,44 @@ public class GridBasicFeatures extends AbstractComponentTest { protected void createRowActions() { createCategory("Body rows", null); - createClickAction("Add first row", "Body rows", + final Command newRowCommand = new Command() { + @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 itemProperty = getProperty(item, i); + itemProperty.setValue("newcell: " + i); + } else if (Integer.class.isAssignableFrom(type)) { + Property itemProperty = getProperty(item, i); + itemProperty.setValue(Integer.valueOf(i)); + } else { + // let the default value be taken implicitly. + } + } + } + + private Property getProperty(Item item, int i) { + @SuppressWarnings("unchecked") + Property itemProperty = item + .getItemProperty(getColumnProperty(i)); + return itemProperty; + } + }; + + createClickAction("Add 18 rows", "Body rows", new Command() { @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 itemProperty = getProperty( - item, i); - itemProperty.setValue("newcell: " + i); - } else if (Integer.class.isAssignableFrom(type)) { - Property itemProperty = getProperty( - item, i); - itemProperty.setValue(Integer.valueOf(i)); - } else { - // let the default value be taken implicitly. - } + for (int i = 0; i < 18; i++) { + newRowCommand.execute(c, value, data); } } - - private Property getProperty( - Item item, int i) { - @SuppressWarnings("unchecked") - Property itemProperty = item - .getItemProperty(getColumnProperty(i)); - return itemProperty; - } }, null); + createClickAction("Add first row", "Body rows", newRowCommand, null); + createClickAction("Remove first row", "Body rows", new Command() { @Override diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java index 8952b04d02..56f5f63c39 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java @@ -111,7 +111,7 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { } } - private WebElement getGridVerticalScrollbar() { + 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/server/GridStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java index 7c5607d4e6..a3cbaa980d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java @@ -18,6 +18,7 @@ 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; @@ -208,6 +209,28 @@ public class GridStructureTest extends GridBasicFeaturesTest { .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)); -- cgit v1.2.3 From 9fb9ff6cc6b28c6b0664c08f2418df834e870eb7 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Fri, 22 Aug 2014 15:52:01 +0300 Subject: Scroll non-visible rows to view when opened for editing (#13334) Change-Id: I5355b9e37d5e7590b002b954804252597ead54c3 --- .../src/com/vaadin/client/ui/grid/EditorRow.java | 35 +++++++++++++++++----- client/src/com/vaadin/client/ui/grid/Grid.java | 7 ----- .../com/vaadin/client/ui/grid/RowContainer.java | 5 ++-- .../basicfeatures/client/GridEditorRowTest.java | 14 +++++++-- 4 files changed, 42 insertions(+), 19 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/EditorRow.java b/client/src/com/vaadin/client/ui/grid/EditorRow.java index 45374962b7..65e0eab0c1 100644 --- a/client/src/com/vaadin/client/ui/grid/EditorRow.java +++ b/client/src/com/vaadin/client/ui/grid/EditorRow.java @@ -82,10 +82,10 @@ public class EditorRow { boolean rowVisible = grid.getEscalator().getVisibleRowRange() .contains(rowIndex); - if (!rowVisible) { - grid.scrollToRow(rowIndex, ScrollDestination.MIDDLE); + if (rowVisible) { + show(); } else { - grid.getEscalator().getBody().refreshRows(rowIndex, 1); + grid.scrollToRow(rowIndex, ScrollDestination.MIDDLE); } } @@ -96,14 +96,16 @@ public class EditorRow { * if this editor row is not in edit mode */ public void cancel() { + if (!enabled) { + throw new IllegalStateException( + "Cannot cancel edit: EditorRow is not enabled"); + } if (state == State.INACTIVE) { throw new IllegalStateException( "Cannot cancel edit: EditorRow is not in edit mode"); } - state = State.INACTIVE; hideOverlay(); - - grid.getEscalator().getBody().refreshRows(rowIndex, 1); + state = State.INACTIVE; } public boolean isEnabled() { @@ -127,8 +129,27 @@ public class EditorRow { this.enabled = enabled; } - protected void setGrid(Grid grid) { + protected void show() { + if (state == State.ACTIVATING) { + state = State.ACTIVE; + showOverlay(grid.getEscalator().getBody().getRowElement(rowIndex)); + } + } + + protected void setGrid(final Grid grid) { + assert grid != null : "Grid cannot be null"; + assert this.grid == null : "Can only attach EditorRow to Grid once"; + this.grid = grid; + + grid.addDataAvailableHandler(new DataAvailableHandler() { + @Override + public void onDataAvailable(DataAvailableEvent event) { + if (event.getAvailableRows().contains(rowIndex)) { + show(); + } + } + }); } protected State getState() { diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index f1de8ca7c7..aa5215bef8 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -1001,13 +1001,6 @@ public class Grid extends Composite implements cell.getElement().removeAllChildren(); } } - - if (rowIndex == editorRow.getRow()) { - if (editorRow.getState() == State.ACTIVATING) { - editorRow.setState(State.ACTIVE); - editorRow.showOverlay(rowElement); - } - } } @Override diff --git a/client/src/com/vaadin/client/ui/grid/RowContainer.java b/client/src/com/vaadin/client/ui/grid/RowContainer.java index d0fb0db103..8b03ef3c36 100644 --- a/client/src/com/vaadin/client/ui/grid/RowContainer.java +++ b/client/src/com/vaadin/client/ui/grid/RowContainer.java @@ -17,6 +17,7 @@ package com.vaadin.client.ui.grid; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.TableRowElement; /** * A representation of the rows in each of the sections (header, body and @@ -182,8 +183,8 @@ public interface RowContainer { * @throws IllegalStateException * if {@code index} is currently not available in the DOM */ - public Element getRowElement(int index) throws IndexOutOfBoundsException, - IllegalStateException; + public TableRowElement getRowElement(int index) + throws IndexOutOfBoundsException, IllegalStateException; /** * Returns the root element of RowContainer 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 index d285bf5c6c..29b5ff8f1b 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java @@ -17,20 +17,28 @@ package com.vaadin.tests.components.grid.basicfeatures.client; import static org.junit.Assert.assertNotNull; +import org.junit.Before; import org.junit.Test; import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest; public class GridEditorRowTest extends GridBasicClientFeaturesTest { - @Test - public void testEditorRowOpening() throws Exception { + @Before + public void setUp() { openTestURL(); - selectMenuPath("Component", "State", "Editor row", "Enabled"); + } + @Test + public void testProgrammaticOpening() throws Exception { selectMenuPath("Component", "State", "Editor row", "Edit row 5"); + assertNotNull(getEditorRow()); + } + @Test + public void testProgrammaticOpeningWithScroll() throws Exception { + selectMenuPath("Component", "State", "Editor row", "Edit row 100"); assertNotNull(getEditorRow()); } } -- cgit v1.2.3 From bd863fc107338df5220e7db32d4c4ae4cfb7a966 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 27 Aug 2014 12:57:01 +0300 Subject: Lock vertical scrolling while editor row is open (#13334) Change-Id: Iee614d21b900900c7d969eca964f5fef829c70f2 --- client/src/com/vaadin/client/ui/grid/EditorRow.java | 3 +++ .../components/grid/basicfeatures/client/GridEditorRowTest.java | 7 +++++++ 2 files changed, 10 insertions(+) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/EditorRow.java b/client/src/com/vaadin/client/ui/grid/EditorRow.java index 65e0eab0c1..c57ae26ff3 100644 --- a/client/src/com/vaadin/client/ui/grid/EditorRow.java +++ b/client/src/com/vaadin/client/ui/grid/EditorRow.java @@ -24,6 +24,7 @@ import com.google.gwt.dom.client.TableRowElement; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.DOM; import com.vaadin.client.ui.grid.Escalator.AbstractRowContainer; +import com.vaadin.client.ui.grid.ScrollbarBundle.Direction; import com.vaadin.shared.ui.grid.ScrollDestination; /** @@ -105,6 +106,7 @@ public class EditorRow { "Cannot cancel edit: EditorRow is not in edit mode"); } hideOverlay(); + grid.getEscalator().setScrollLocked(Direction.VERTICAL, false); state = State.INACTIVE; } @@ -132,6 +134,7 @@ public class EditorRow { protected void show() { if (state == State.ACTIVATING) { state = State.ACTIVE; + grid.getEscalator().setScrollLocked(Direction.VERTICAL, true); showOverlay(grid.getEscalator().getBody().getRowElement(rowIndex)); } } 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 index 29b5ff8f1b..579d00dfd2 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertNotNull; import org.junit.Before; import org.junit.Test; +import org.openqa.selenium.NoSuchElementException; import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest; @@ -41,4 +42,10 @@ public class GridEditorRowTest extends GridBasicClientFeaturesTest { selectMenuPath("Component", "State", "Editor row", "Edit row 100"); assertNotNull(getEditorRow()); } + + @Test(expected = NoSuchElementException.class) + public void testVerticalScrollLocking() throws Exception { + selectMenuPath("Component", "State", "Editor row", "Edit row 5"); + getGridElement().getCell(200, 0); + } } -- cgit v1.2.3 From 600d5b436d7ca33840b1b697082d140a5040bdf3 Mon Sep 17 00:00:00 2001 From: Patrik Lindström Date: Mon, 25 Aug 2014 14:44:12 +0300 Subject: Add keyboard sorting controls (#13334) Change-Id: Icb0ef5d70b5469cd87bdd079fe16f31b8cf769f1 --- client/src/com/vaadin/client/ui/grid/Grid.java | 56 ++++++++++++++++-- .../com/vaadin/client/ui/grid/sort/SortOrder.java | 20 +++++++ .../com/vaadin/shared/ui/grid/SortDirection.java | 21 ++++++- .../grid/basicfeatures/server/GridSortingTest.java | 69 ++++++++++++++++++++++ 4 files changed, 159 insertions(+), 7 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index aa5215bef8..34bff2fd45 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -1265,6 +1265,50 @@ public class Grid extends Composite implements sinkEvents(getHeader().getConsumedEvents()); sinkEvents(Arrays.asList(BrowserEvents.KEYDOWN, BrowserEvents.KEYUP, BrowserEvents.KEYPRESS)); + + // Make ENTER and SHIFT+ENTER in the header perform sorting + addKeyUpHandler(new HeaderKeyUpHandler() { + @Override + public void onKeyUp(GridKeyUpEvent event) { + if (event.getNativeKeyCode() != KeyCodes.KEY_ENTER) { + return; + } + + final Cell cell = event.getActiveCell(); + final GridColumn column = columns.get(cell.getColumn()); + + // If SHIFT is down, we modify multi-sorting order + if (event.isShiftKeyDown() && sortOrder != null) { + + final SortOrder so = getSortOrder(column); + + if (so != null) { + // Flip sort direction in-place + final int idx = sortOrder.indexOf(so); + sortOrder.set(idx, so.getOpposite()); + } else { + // Add a new sort rule to the end of the list + sortOrder.add(new SortOrder(column)); + } + + } else { + if (sortOrder.size() == 1 + && sortOrder.get(0).getColumn() == column) { + + // Reverse the sort order and re-sort + sortOrder.set(0, sortOrder.get(0).getOpposite()); + } else { + + // Manually re-set the sorting order + sortOrder.clear(); + sortOrder.add(new SortOrder(column)); + } + } + + // We've modified the sort order, re-sort it now. + setSortOrder(sortOrder, SortEventOriginator.USER); + } + }); } @Override @@ -2083,8 +2127,8 @@ public class Grid extends Composite implements private Point rowEventTouchStartingPoint; - private boolean handleHeaderDefaultRowEvent(Event event, RowContainer container, - final Cell cell) { + private boolean handleHeaderDefaultRowEvent(Event event, + RowContainer container, final Cell cell) { if (container != escalator.getHeader()) { return false; } @@ -2488,9 +2532,11 @@ public class Grid extends Composite implements private void setSortOrder(List order, SortEventOriginator originator) { - sortOrder.clear(); - if (order != null) { - sortOrder.addAll(order); + if (order != sortOrder) { + sortOrder.clear(); + if (order != null) { + sortOrder.addAll(order); + } } sort(originator); } diff --git a/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java index 682beda793..8878e18872 100644 --- a/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java +++ b/client/src/com/vaadin/client/ui/grid/sort/SortOrder.java @@ -31,6 +31,17 @@ public class SortOrder { private final GridColumn column; private final SortDirection direction; + /** + * Create a sort order descriptor with a default sorting direction value of + * {@link SortDirection#ASCENDING}. + * + * @param column + * a grid column descriptor object + */ + public SortOrder(GridColumn column) { + this(column, SortDirection.ASCENDING); + } + /** * Create a sort order descriptor. * @@ -69,4 +80,13 @@ public class SortOrder { public SortDirection getDirection() { return direction; } + + /** + * Returns a new SortOrder object with the sort direction reversed. + * + * @return a new sort order object + */ + public SortOrder getOpposite() { + return new SortOrder(column, direction.getOpposite()); + } } diff --git a/shared/src/com/vaadin/shared/ui/grid/SortDirection.java b/shared/src/com/vaadin/shared/ui/grid/SortDirection.java index 0b4eafc37f..9aed268d01 100644 --- a/shared/src/com/vaadin/shared/ui/grid/SortDirection.java +++ b/shared/src/com/vaadin/shared/ui/grid/SortDirection.java @@ -28,10 +28,27 @@ public enum SortDirection implements Serializable { /** * Ascending (e.g. A-Z, 1..9) sort order */ - ASCENDING, + ASCENDING { + @Override + public SortDirection getOpposite() { + return DESCENDING; + } + }, /** * Descending (e.g. Z-A, 9..1) sort order */ - DESCENDING + DESCENDING { + @Override + public SortDirection getOpposite() { + return ASCENDING; + } + }; + + /** + * Get the sort direction that is the direct opposite to this one. + * + * @return a sort direction value + */ + public abstract SortDirection getOpposite(); } 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 index 024be65e83..74a5c6ed95 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java @@ -191,6 +191,75 @@ public class GridSortingTest extends GridBasicFeaturesTest { } + 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 testKeyboardMultiColumnSorting() throws InterruptedException { + 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); + + // Reset sorting to third column, ASCENDING + sendKeys(Keys.ENTER); + assertLog("10. Sort order: [Column 2 ASCENDING] by USER"); + + } + private void sortBy(String column) { selectMenuPath("Component", "State", "Sort by column", column); } -- cgit v1.2.3 From 1e282eed6be3f2aa84ce0da512b6bd8a768b90e1 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 28 Aug 2014 16:36:33 +0300 Subject: Add handler adding functions for all GridKeyEvents (#13334) Change-Id: Ic237af24e3d9d35127b01d380b81b9f12ca4c520 --- client/src/com/vaadin/client/ui/grid/Grid.java | 137 +++++++++++++++------ .../ui/grid/selection/MultiSelectionRenderer.java | 4 +- .../client/grid/GridBasicClientFeaturesWidget.java | 18 +-- 3 files changed, 109 insertions(+), 50 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 34bff2fd45..a9ae570736 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -53,9 +53,6 @@ import com.vaadin.client.ui.grid.GridFooter.FooterRow; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler; -import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyDownHandler; -import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyPressHandler; -import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler.GridKeyUpHandler; import com.vaadin.client.ui.grid.events.BodyKeyDownHandler; import com.vaadin.client.ui.grid.events.BodyKeyPressHandler; import com.vaadin.client.ui.grid.events.BodyKeyUpHandler; @@ -2601,63 +2598,125 @@ public class Grid extends Composite implements } /** - * Register a KeyDown handler to this Grid. If the handler is a - * HeaderKeyDownHandler, it will be fired only when a header cell is active. - * The same goes for body and footer with their respective handlers. + * Register a BodyKeyDownHandler to this Grid. The event for this handler is + * fired when a KeyDown event occurs while active cell is in the Body of + * this Grid. * * @param handler * the key handler to register * @return the registration for the event */ - public HandlerRegistration addKeyDownHandler( - HANDLER handler) { - if (handler instanceof BodyKeyDownHandler - || handler instanceof HeaderKeyDownHandler - || handler instanceof FooterKeyDownHandler) { - return addHandler(handler, keyDown.getAssociatedType()); - } - throw new IllegalArgumentException( - "Handler not a valid extension of GridKeyDownHandler"); + public HandlerRegistration addBodyKeyDownHandler(BodyKeyDownHandler handler) { + return addHandler(handler, keyDown.getAssociatedType()); } /** - * Register a KeyUp handler to this Grid. If the handler is a - * HeaderKeyUpHandler, it will be fired only when a header cell is active. - * The same goes for body and footer with their respective handlers. + * Register a BodyKeyUpHandler to this Grid. The event for this handler is + * fired when a KeyUp event occurs while active cell is in the Body of this + * Grid. * * @param handler * the key handler to register * @return the registration for the event */ - public HandlerRegistration addKeyUpHandler( - HANDLER handler) { - if (handler instanceof BodyKeyUpHandler - || handler instanceof HeaderKeyUpHandler - || handler instanceof FooterKeyUpHandler) { - return addHandler(handler, keyUp.getAssociatedType()); - } - throw new IllegalArgumentException( - "Handler not a valid extension of GridKeyUpHandler"); + public HandlerRegistration addBodyKeyUpHandler(BodyKeyUpHandler handler) { + return addHandler(handler, keyUp.getAssociatedType()); } /** - * Register a KeyPress handler to this Grid. If the handler is a - * HeaderKeyPressHandler, it will be fired only when a header cell is - * active. The same goes for body and footer with their respective handlers. + * Register a BodyKeyPressHandler to this Grid. The event for this handler + * is fired when a KeyPress event occurs while active cell is in the Body of + * this Grid. * * @param handler * the key handler to register * @return the registration for the event */ - public HandlerRegistration addKeyPressHandler( - HANDLER handler) { - if (handler instanceof BodyKeyPressHandler - || handler instanceof HeaderKeyPressHandler - || handler instanceof FooterKeyPressHandler) { - return addHandler(handler, keyPress.getAssociatedType()); - } - throw new IllegalArgumentException( - "Handler not a valid extension of GridKeyPressHandler"); + public HandlerRegistration addBodyKeyPressHandler( + BodyKeyPressHandler handler) { + return addHandler(handler, keyPress.getAssociatedType()); + } + + /** + * Register a HeaderKeyDownHandler to this Grid. The event for this handler + * is fired when a KeyDown event occurs while active cell is in the Header + * of this Grid. + * + * @param handler + * the key handler to register + * @return the registration for the event + */ + public HandlerRegistration addHeaderKeyDownHandler( + HeaderKeyDownHandler handler) { + return addHandler(handler, keyDown.getAssociatedType()); + } + + /** + * Register a HeaderKeyUpHandler to this Grid. The event for this handler is + * fired when a KeyUp event occurs while active cell is in the Header of + * this Grid. + * + * @param handler + * the key handler to register + * @return the registration for the event + */ + public HandlerRegistration addHeaderKeyUpHandler(HeaderKeyUpHandler handler) { + return addHandler(handler, keyUp.getAssociatedType()); + } + + /** + * Register a HeaderKeyPressHandler to this Grid. The event for this handler + * is fired when a KeyPress event occurs while active cell is in the Header + * of this Grid. + * + * @param handler + * the key handler to register + * @return the registration for the event + */ + public HandlerRegistration addHeaderKeyPressHandler( + HeaderKeyPressHandler handler) { + return addHandler(handler, keyPress.getAssociatedType()); + } + + /** + * Register a FooterKeyDownHandler to this Grid. The event for this handler + * is fired when a KeyDown event occurs while active cell is in the Footer + * of this Grid. + * + * @param handler + * the key handler to register + * @return the registration for the event + */ + public HandlerRegistration addFooterKeyDownHandler( + FooterKeyDownHandler handler) { + return addHandler(handler, keyDown.getAssociatedType()); + } + + /** + * Register a FooterKeyUpHandler to this Grid. The event for this handler is + * fired when a KeyUp event occurs while active cell is in the Footer of + * this Grid. + * + * @param handler + * the key handler to register + * @return the registration for the event + */ + public HandlerRegistration addFooterKeyUpHandler(FooterKeyUpHandler handler) { + return addHandler(handler, keyUp.getAssociatedType()); + } + + /** + * Register a FooterKeyPressHandler to this Grid. The event for this handler + * is fired when a KeyPress event occurs while active cell is in the Footer + * of this Grid. + * + * @param handler + * the key handler to register + * @return the registration for the event + */ + public HandlerRegistration addFooterKeyPressHandler( + FooterKeyPressHandler handler) { + return addHandler(handler, keyPress.getAssociatedType()); } /** diff --git a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java index 1a531aa3ca..a18c8dafb0 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java @@ -636,8 +636,8 @@ public class MultiSelectionRenderer extends ComplexRenderer { public MultiSelectionRenderer(final Grid grid) { this.grid = grid; - spaceDown = grid.addKeyDownHandler(handler); - spaceUp = grid.addKeyUpHandler(new BodyKeyUpHandler() { + spaceDown = grid.addBodyKeyDownHandler(handler); + spaceUp = grid.addBodyKeyUpHandler(new BodyKeyUpHandler() { @Override public void onKeyUp(GridKeyUpEvent event) { diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index 88d406c0f8..ac1572ab14 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -711,7 +711,7 @@ public class GridBasicClientFeaturesWidget extends } // Key Down Events - grid.addKeyDownHandler(new BodyKeyDownHandler() { + grid.addBodyKeyDownHandler(new BodyKeyDownHandler() { private final VLabel label = labels.get(0); @Override @@ -720,7 +720,7 @@ public class GridBasicClientFeaturesWidget extends } }); - grid.addKeyDownHandler(new HeaderKeyDownHandler() { + grid.addHeaderKeyDownHandler(new HeaderKeyDownHandler() { private final VLabel label = labels.get(1); @Override @@ -729,7 +729,7 @@ public class GridBasicClientFeaturesWidget extends } }); - grid.addKeyDownHandler(new FooterKeyDownHandler() { + grid.addFooterKeyDownHandler(new FooterKeyDownHandler() { private final VLabel label = labels.get(2); @Override @@ -739,7 +739,7 @@ public class GridBasicClientFeaturesWidget extends }); // Key Up Events - grid.addKeyUpHandler(new BodyKeyUpHandler() { + grid.addBodyKeyUpHandler(new BodyKeyUpHandler() { private final VLabel label = labels.get(3); @Override @@ -748,7 +748,7 @@ public class GridBasicClientFeaturesWidget extends } }); - grid.addKeyUpHandler(new HeaderKeyUpHandler() { + grid.addHeaderKeyUpHandler(new HeaderKeyUpHandler() { private final VLabel label = labels.get(4); @Override @@ -757,7 +757,7 @@ public class GridBasicClientFeaturesWidget extends } }); - grid.addKeyUpHandler(new FooterKeyUpHandler() { + grid.addFooterKeyUpHandler(new FooterKeyUpHandler() { private final VLabel label = labels.get(5); @Override @@ -767,7 +767,7 @@ public class GridBasicClientFeaturesWidget extends }); // Key Press Events - grid.addKeyPressHandler(new BodyKeyPressHandler() { + grid.addBodyKeyPressHandler(new BodyKeyPressHandler() { private final VLabel label = labels.get(6); @Override @@ -776,7 +776,7 @@ public class GridBasicClientFeaturesWidget extends } }); - grid.addKeyPressHandler(new HeaderKeyPressHandler() { + grid.addHeaderKeyPressHandler(new HeaderKeyPressHandler() { private final VLabel label = labels.get(7); @Override @@ -785,7 +785,7 @@ public class GridBasicClientFeaturesWidget extends } }); - grid.addKeyPressHandler(new FooterKeyPressHandler() { + grid.addFooterKeyPressHandler(new FooterKeyPressHandler() { private final VLabel label = labels.get(8); @Override -- cgit v1.2.3 From afe2cb5530b474940540a10a769d4b3cba29be31 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 26 Aug 2014 09:21:23 +0300 Subject: Make Grid call ComplexRenderer.onActivate when needed (#13334) Change-Id: Icd2ecbdb0780ba97e0955eb7c564f8f56ca14109 --- client/src/com/vaadin/client/ui/grid/Grid.java | 75 ++++++++++++++-------- .../client/ui/grid/renderers/ComplexRenderer.java | 10 +-- .../tests/components/grid/GridClientRenderers.java | 21 ++++++ .../server/GridStaticSectionComponentTest.java | 3 +- .../grid/GridClientColumnRendererConnector.java | 7 ++ 5 files changed, 85 insertions(+), 31 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index b3e2fd8a94..1ed5cb8a75 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -372,8 +372,9 @@ public class Grid extends Composite implements * Handle events that can change the currently active cell. */ public void handleNavigationEvent(Event event, Cell cell) { - if (event.getType().equals(BrowserEvents.CLICK) && cell != null) { + if (event.getType().equals(BrowserEvents.CLICK)) { setActiveCell(cell); + // Grid should have focus when clicked. getElement().focus(); } else if (event.getType().equals(BrowserEvents.KEYDOWN)) { int newRow = activeRow; @@ -1261,7 +1262,7 @@ public class Grid extends Composite implements // Sink header events and key events sinkEvents(getHeader().getConsumedEvents()); sinkEvents(Arrays.asList(BrowserEvents.KEYDOWN, BrowserEvents.KEYUP, - BrowserEvents.KEYPRESS)); + BrowserEvents.KEYPRESS, BrowserEvents.DBLCLICK)); // Make ENTER and SHIFT+ENTER in the header perform sorting addHeaderKeyUpHandler(new HeaderKeyUpHandler() { @@ -1994,26 +1995,35 @@ public class Grid extends Composite implements Element e = Element.as(target); RowContainer container = escalator.findRowContainer(e); - Cell cell = container != null ? container.getCell(e) : null; - - if (handleEditorRowEvent(event, container, cell)) { - return; + Cell cell; + boolean isGrid = Util.findWidget(e, null) == this; + if (container == null) { + cell = activeCellHandler.getActiveCell(); + container = activeCellHandler.container; + } else { + cell = container.getCell(e); } - if (handleHeaderDefaultRowEvent(event, container, cell)) { - return; - } + if (isGrid) { + if (handleEditorRowEvent(event, container, cell)) { + return; + } - if (handleRendererEvent(event, container, cell)) { - return; - } + if (handleHeaderDefaultRowEvent(event, container, cell)) { + return; + } - if (handleNavigationEvent(event, container, cell)) { - return; - } + if (handleRendererEvent(event, container, cell)) { + return; + } - if (handleActiveCellEvent(event, container, cell)) { - return; + if (handleNavigationEvent(event, container, cell)) { + return; + } + + if (handleActiveCellEvent(event, container, cell)) { + return; + } } } @@ -2047,6 +2057,10 @@ public class Grid extends Composite implements if (container == escalator.getBody() && cell != null) { GridColumn gridColumn = getColumnFromVisibleIndex(cell .getColumn()); + boolean enterKey = event.getType().equals(BrowserEvents.KEYDOWN) + && event.getKeyCode() == KeyCodes.KEY_ENTER; + boolean doubleClick = event.getType() + .equals(BrowserEvents.DBLCLICK); if (gridColumn.getRenderer() instanceof ComplexRenderer) { ComplexRenderer cplxRenderer = (ComplexRenderer) gridColumn @@ -2056,6 +2070,11 @@ public class Grid extends Composite implements return true; } } + + // Calls onActivate if KeyDown and Enter or double click + if ((enterKey || doubleClick) && cplxRenderer.onActivate(cell)) { + return true; + } } } return false; @@ -2064,8 +2083,7 @@ public class Grid extends Composite implements private boolean handleActiveCellEvent(Event event, RowContainer container, Cell cell) { Collection navigation = activeCellHandler.getNavigationEvents(); - if (navigation.contains(event.getType()) - && (Util.getFocusedElement() == getElement() || cell != null)) { + if (navigation.contains(event.getType())) { activeCellHandler.handleNavigationEvent(event, cell); } return false; @@ -2152,6 +2170,8 @@ public class Grid extends Composite implements lazySorter.setMultisort(true); lazySorter.schedule(GridConstants.LONG_TAP_DELAY); + return true; + } else if (BrowserEvents.TOUCHMOVE.equals(event.getType())) { if (event.getTouches().length() > 1) { return false; @@ -2172,8 +2192,10 @@ public class Grid extends Composite implements lazySorter.cancel(); } + return true; + } else if (BrowserEvents.TOUCHEND.equals(event.getType())) { - if (event.getTouches().length() > 0) { + if (event.getTouches().length() > 1) { return false; } @@ -2184,24 +2206,27 @@ public class Grid extends Composite implements lazySorter.run(); } + return true; + } else if (BrowserEvents.TOUCHCANCEL.equals(event.getType())) { - if (event.getChangedTouches().length() > 1) { + if (event.getTouches().length() > 1) { return false; } lazySorter.cancel(); + return true; + } else if (BrowserEvents.CLICK.equals(event.getType())) { lazySorter.setCellReference(cell); lazySorter.setMultisort(event.getShiftKey()); lazySorter.run(); - // Active cell handling is also monitoring the click - // event so we allow event to propagate for it + // Click events should go onward to active cell logic + return false; + } else { return false; } - - return true; } @Override diff --git a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java index f0c95e2ddf..ed9aefd260 100644 --- a/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/renderers/ComplexRenderer.java @@ -16,6 +16,7 @@ package com.vaadin.client.ui.grid.renderers; import java.util.Collection; +import java.util.Collections; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; @@ -70,14 +71,13 @@ public abstract class ComplexRenderer implements Renderer { * Returns the events that the renderer should consume. These are also the * events that the Grid will pass to * {@link #onBrowserEvent(Cell, NativeEvent)} when they occur. - * null if no events are consumed * - * @return the consumed events, or null if no events are consumed + * @return a list of consumed events * * @see com.google.gwt.dom.client.BrowserEvents */ public Collection getConsumedEvents() { - return null; + return Collections.emptyList(); } /** @@ -136,10 +136,12 @@ public abstract class ComplexRenderer implements Renderer { * Called when the cell is "activated" by pressing enter, * double clicking or performing a double tap on the cell. * + * @param cell + * the activated cell * @return true if event was handled and should not be * interpreted as a generic gesture by Grid. */ - public boolean onActivate() { + public boolean onActivate(Cell cell) { return false; } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java index fd3c8d5b2f..2656407023 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridClientRenderers.java @@ -21,7 +21,9 @@ 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; @@ -31,6 +33,7 @@ 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; @@ -248,6 +251,24 @@ public class GridClientRenderers extends MultiBrowserTest { } } + @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(); } 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 index 19a68a87f4..21bf667bae 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java @@ -35,8 +35,7 @@ public class GridStaticSectionComponentTest extends GridBasicFeaturesTest { getGridElement().$(ButtonElement.class).first().click(); - // Clicking also triggers sorting - assertEquals("2. Button clicked!", getLogRow(2)); + assertEquals("2. Button clicked!", getLogRow(0)); } @Test diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index 7a9f8a06f5..c5571394bd 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -31,6 +31,7 @@ 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; @@ -331,6 +332,12 @@ public class GridClientColumnRendererConnector extends super.setContentVisible(cell, hasData); } + + @Override + public boolean onActivate(Cell cell) { + cell.getElement().setInnerHTML("Activated!"); + return true; + } }; default: -- cgit v1.2.3 From 5fee7abda87b4a18bab6e20de263640fa3ff0f86 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Mon, 8 Sep 2014 14:33:48 +0300 Subject: Pass editor row enabled state in shared state (#13334) Also refactor editor row tests a bit. Include separate GWT and Vaadin test cases at least until communication is finished. Change-Id: I5fd2288e20b11ba5bc33d074f7fe086dc3f00323 --- .../com/vaadin/client/ui/grid/GridConnector.java | 4 ++ .../com/vaadin/ui/components/grid/EditorRow.java | 39 ++++++------ server/src/com/vaadin/ui/components/grid/Grid.java | 2 +- .../src/com/vaadin/shared/ui/grid/GridState.java | 3 + .../grid/basicfeatures/GridBasicFeatures.java | 12 ++++ .../client/GridEditorRowClientTest.java | 74 ++++++++++++++++++++++ .../basicfeatures/client/GridEditorRowTest.java | 36 ++++++----- .../client/grid/GridBasicClientFeaturesWidget.java | 47 +++++++------- 8 files changed, 160 insertions(+), 57 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 72de944848..a06e1df802 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -281,6 +281,10 @@ public class GridConnector extends AbstractHasComponentsConnector { getWidget().setLastFrozenColumn(null); } } + + if (stateChangeEvent.hasPropertyChanged("editorRowEnabled")) { + getWidget().getEditorRow().setEnabled(getState().editorRowEnabled); + } } private void updateSectionFromState(GridStaticSection section, diff --git a/server/src/com/vaadin/ui/components/grid/EditorRow.java b/server/src/com/vaadin/ui/components/grid/EditorRow.java index 5eb38156e2..18a5e8647b 100644 --- a/server/src/com/vaadin/ui/components/grid/EditorRow.java +++ b/server/src/com/vaadin/ui/components/grid/EditorRow.java @@ -37,24 +37,21 @@ import com.vaadin.ui.Field; * @see Grid */ public class EditorRow implements Serializable { - private final Container container; + private Grid grid; - private boolean isEnabled; private FieldGroup fieldGroup = new FieldGroup(); private Object editedItemId = null; - private boolean isDetached = false; - private HashSet uneditableProperties = new HashSet(); /** - * Constructs a new editor row bound to a particular container. + * Constructs a new editor row for the given grid component. * - * @param container - * the container this editor row is bound to + * @param grid + * the grid this editor row is attached to */ - EditorRow(Container container) { - this.container = container; + EditorRow(Grid grid) { + this.grid = grid; } /** @@ -66,7 +63,7 @@ public class EditorRow implements Serializable { */ public boolean isEnabled() { checkDetached(); - return isEnabled; + return grid.getState(false).editorRowEnabled; } /** @@ -86,7 +83,9 @@ public class EditorRow implements Serializable { + "while an item (" + getEditedItemId() + ") is being edited."); } - this.isEnabled = isEnabled; + if (isEnabled() != isEnabled) { + grid.getState().editorRowEnabled = isEnabled; + } } /** @@ -109,7 +108,8 @@ public class EditorRow implements Serializable { checkDetached(); this.fieldGroup = fieldGroup; if (editedItemId != null) { - this.fieldGroup.setItemDataSource(container.getItem(editedItemId)); + this.fieldGroup.setItemDataSource(getContainer().getItem( + editedItemId)); } } @@ -272,7 +272,7 @@ public class EditorRow implements Serializable { */ void detach() { checkDetached(); - isDetached = true; + grid = null; } /** @@ -295,7 +295,7 @@ public class EditorRow implements Serializable { + getClass().getSimpleName() + " is not enabled"); } - Item item = container.getItem(itemId); + Item item = getContainer().getItem(itemId); if (item == null) { throw new IllegalArgumentException("Item with id " + itemId + " not found in current container"); @@ -326,7 +326,6 @@ public class EditorRow implements Serializable { */ Collection> getFields() { checkDetached(); - /* * Maybe this isn't the best idea, however. Maybe the components should * always be transferred over the wire, to increase up-front load-time @@ -346,7 +345,7 @@ public class EditorRow implements Serializable { * might not read-only. */ ArrayList> fields = new ArrayList>(); - for (Object propertyId : container.getContainerPropertyIds()) { + for (Object propertyId : getContainer().getContainerPropertyIds()) { Field field = getField(propertyId); if (field != null) { fields.add(field); @@ -356,8 +355,12 @@ public class EditorRow implements Serializable { return fields; } + private Container getContainer() { + return grid.getContainerDatasource(); + } + private void checkDetached() throws IllegalStateException { - if (isDetached) { + if (grid == null) { throw new IllegalStateException("The method cannot be " + "processed as this " + getClass().getSimpleName() + " has become detached."); @@ -365,7 +368,7 @@ public class EditorRow implements Serializable { } private void checkPropertyExists(Object propertyId) { - if (!container.getContainerPropertyIds().contains(propertyId)) { + if (!getContainer().getContainerPropertyIds().contains(propertyId)) { throw new IllegalArgumentException("Property with id " + propertyId + " is not in the current Container"); } diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 962ea8f499..1a6f333e48 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -428,7 +428,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, if (editorRow != null) { editorRow.detach(); } - editorRow = new EditorRow(datasource); + editorRow = new EditorRow(this); // // Adjust sort order diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index d687dd8e48..4394b575ff 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -127,4 +127,7 @@ public class GridState extends AbstractComponentState { /** Directions for each sorted column */ public SortDirection[] sortDirs = new SortDirection[0]; + + /** The enabled state of the editor row */ + public boolean editorRowEnabled = false; } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index b760f8531c..0802fcffe5 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -200,6 +200,8 @@ public class GridBasicFeatures extends AbstractComponentTest { createRowActions(); + createEditorRowActions(); + addHeightActions(); return grid; @@ -645,6 +647,16 @@ public class GridBasicFeatures extends AbstractComponentTest { }, null); } + protected void createEditorRowActions() { + createBooleanAction("Enabled", "Editor row", false, + new Command() { + @Override + public void execute(Grid c, Boolean value, Object data) { + c.getEditorRow().setEnabled(value); + } + }); + } + @SuppressWarnings("boxing") protected void addHeightActions() { createCategory("Height by Rows", "Size"); 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..5a4568259d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java @@ -0,0 +1,74 @@ +/* + * 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.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.Keys; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest; + +public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { + + @Before + public void setUp() { + openTestURL(); + selectMenuPath("Component", "Editor row", "Enabled"); + } + + @Test + public void testProgrammaticOpening() { + selectMenuPath("Component", "Editor row", "Edit row 5"); + assertNotNull(getEditorRow()); + } + + @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()); + + // Disable editor row + selectMenuPath("Component", "Editor row", "Enabled"); + + getGridElement().getCell(5, 0).click(); + new Actions(getDriver()).sendKeys(Keys.ENTER).perform(); + assertNull(getEditorRow()); + } +} 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 index 579d00dfd2..f82702d432 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java @@ -16,36 +16,40 @@ package com.vaadin.tests.components.grid.basicfeatures.client; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import org.junit.Before; import org.junit.Test; -import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.Keys; +import org.openqa.selenium.interactions.Actions; -import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; -public class GridEditorRowTest extends GridBasicClientFeaturesTest { +public class GridEditorRowTest extends GridBasicFeaturesTest { @Before public void setUp() { openTestURL(); - selectMenuPath("Component", "State", "Editor row", "Enabled"); + selectMenuPath("Component", "Editor row", "Enabled"); } @Test - public void testProgrammaticOpening() throws Exception { - selectMenuPath("Component", "State", "Editor row", "Edit row 5"); - assertNotNull(getEditorRow()); - } + public void testKeyboardOpeningClosing() { + + getGridElement().getCell(4, 0).click(); + + new Actions(getDriver()).sendKeys(Keys.ENTER).perform(); - @Test - public void testProgrammaticOpeningWithScroll() throws Exception { - selectMenuPath("Component", "State", "Editor row", "Edit row 100"); assertNotNull(getEditorRow()); - } - @Test(expected = NoSuchElementException.class) - public void testVerticalScrollLocking() throws Exception { - selectMenuPath("Component", "State", "Editor row", "Edit row 5"); - getGridElement().getCell(200, 0); + 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()); } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index ac1572ab14..a8fa6d1a08 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -253,6 +253,7 @@ public class GridBasicClientFeaturesWidget extends createColumnsMenu(); createHeaderMenu(); createFooterMenu(); + createEditorRowMenu(); createInternalsMenu(); grid.getElement().getStyle().setZIndex(0); @@ -336,28 +337,6 @@ public class GridBasicClientFeaturesWidget extends } }, primaryStyleNamePath); - - addMenuCommand("Enabled", new ScheduledCommand() { - @Override - public void execute() { - grid.getEditorRow() - .setEnabled(!grid.getEditorRow().isEnabled()); - } - }, "Component", "State", "Editor row"); - - addMenuCommand("Edit row 5", new ScheduledCommand() { - @Override - public void execute() { - grid.getEditorRow().editRow(5); - } - }, "Component", "State", "Editor row"); - - addMenuCommand("Edit row 100", new ScheduledCommand() { - @Override - public void execute() { - grid.getEditorRow().editRow(100); - } - }, "Component", "State", "Editor row"); } private void createColumnsMenu() { @@ -635,6 +614,30 @@ public class GridBasicClientFeaturesWidget extends }, 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"); + } + private void configureFooterRow(final FooterRow row) { final GridFooter footer = grid.getFooter(); setFooterTexts(row); -- cgit v1.2.3 From ee8f4a650f978ced2e390697c5013f0fbfdc1111 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 3 Sep 2014 10:59:11 +0300 Subject: Adjust active cell on body row add/remove (#13334) Change-Id: I909f5b2113d8d970a0517f100eb0a31778a62681 --- client/src/com/vaadin/client/ui/grid/Grid.java | 53 ++++++++++++++++++++++ .../server/GridActiveCellAdjustmentTest.java | 49 ++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridActiveCellAdjustmentTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 10d56c92fc..478e7b4a9d 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -288,6 +288,7 @@ public class Grid extends Composite implements private void setActiveCell(int row, int column, RowContainer container) { if (row == activeRow && activeCellRange.contains(column) && container == this.container) { + refreshRow(activeRow); return; } @@ -508,6 +509,54 @@ public class Grid extends Composite implements public void offsetRangeBy(int offset) { activeCellRange = activeCellRange.offsetBy(offset); } + + /* + * Informs ActiveCellHandler that certain range of rows has been added. + * ActiveCellHandler will fix indices accordingly. + * + * @param added a range of added rows + */ + public void rowsAdded(Range added) { + if (added.getStart() <= activeRow) { + setActiveCell(activeRow + added.length(), + activeCellRange.getStart(), container); + } + } + + /** + * Informs ActiveCellHandler that certain range of rows has been + * removed. ActiveCellHandler will fix indices accordingly. + * + * @param removed + * a range of removed rows + */ + public void rowsRemoved(Range removed) { + int activeColumn = activeCellRange.getStart(); + if (container != escalator.getBody()) { + return; + } else if (!removed.contains(activeRow)) { + if (removed.getStart() > activeRow) { + return; + } + setActiveCell(activeRow - removed.length(), activeColumn, + container); + } else { + if (container.getRowCount() > removed.getEnd()) { + setActiveCell(removed.getStart(), activeColumn, container); + } else if (removed.getStart() > 0) { + setActiveCell(removed.getStart() - 1, activeColumn, + container); + } else { + if (escalator.getHeader().getRowCount() > 0) { + setActiveCell(lastActiveHeaderRow, activeColumn, + escalator.getHeader()); + } else if (escalator.getFooter().getRowCount() > 0) { + setActiveCell(lastActiveFooterRow, activeColumn, + escalator.getFooter()); + } + } + } + } } private class SelectionColumn extends GridColumn { @@ -1707,11 +1756,15 @@ public class Grid extends Composite implements @Override public void dataRemoved(int firstIndex, int numberOfItems) { escalator.getBody().removeRows(firstIndex, numberOfItems); + Range removed = Range.withLength(firstIndex, numberOfItems); + activeCellHandler.rowsRemoved(removed); } @Override public void dataAdded(int firstIndex, int numberOfItems) { escalator.getBody().insertRows(firstIndex, numberOfItems); + Range added = Range.withLength(firstIndex, numberOfItems); + activeCellHandler.rowsAdded(added); } @Override 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()); + } + } + +} -- cgit v1.2.3 From e6c32d7ab4fa308af471efb26ad50c0d84ebf568 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Mon, 1 Sep 2014 14:50:07 +0300 Subject: Restructures Escalator testing rig (#13334) Change-Id: I75b5e20158475b739c2d37d4fdf4865425dc3693 --- .../tests/components/grid/BasicEscalator.java | 319 ------------- .../tests/components/grid/BasicEscalatorTest.java | 295 ------------ .../EscalatorBasicClientFeatures.java | 36 ++ .../EscalatorBasicClientFeaturesConnector.java | 37 ++ .../grid/EscalatorBasicClientFeaturesWidget.java | 506 +++++++++++++++++++++ .../widgetset/client/grid/EscalatorProxy.java | 239 ++++++++++ .../widgetset/client/grid/TestGridClientRpc.java | 48 -- .../widgetset/client/grid/TestGridConnector.java | 138 ------ .../tests/widgetset/client/grid/TestGridState.java | 29 -- .../tests/widgetset/client/grid/VTestGrid.java | 249 ---------- .../tests/widgetset/server/grid/TestGrid.java | 96 ---- 11 files changed, 818 insertions(+), 1174 deletions(-) delete mode 100644 uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java delete mode 100644 uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeatures.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesConnector.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java delete mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridClientRpc.java delete mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java delete mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java delete mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java delete mode 100644 uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java deleted file mode 100644 index f7af6a57e5..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalator.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.vaadin.tests.components.grid; - -import java.util.Random; - -import com.vaadin.annotations.Widgetset; -import com.vaadin.server.VaadinRequest; -import com.vaadin.tests.components.AbstractTestUI; -import com.vaadin.tests.widgetset.TestingWidgetSet; -import com.vaadin.tests.widgetset.server.grid.TestGrid; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.HorizontalLayout; -import com.vaadin.ui.Layout; -import com.vaadin.ui.NativeSelect; -import com.vaadin.ui.TextField; - -@Widgetset(TestingWidgetSet.NAME) -public class BasicEscalator extends AbstractTestUI { - public static final String ESCALATOR = "escalator"; - - public static final String INSERT_ROWS_OFFSET = "iro"; - public static final String INSERT_ROWS_AMOUNT = "ira"; - public static final String INSERT_ROWS_BUTTON = "irb"; - - public static final String REMOVE_ROWS_OFFSET = "rro"; - public static final String REMOVE_ROWS_AMOUNT = "rra"; - public static final String REMOVE_ROWS_BUTTON = "rrb"; - - private final Random random = new Random(); - - @Override - protected void setup(final VaadinRequest request) { - final TestGrid grid = new TestGrid(); - grid.setId(ESCALATOR); - addComponent(grid); - - final Layout insertRowsLayout = new HorizontalLayout(); - final TextField insertRowsOffset = new TextField(); - insertRowsOffset.setId(INSERT_ROWS_OFFSET); - insertRowsLayout.addComponent(insertRowsOffset); - final TextField insertRowsAmount = new TextField(); - insertRowsAmount.setId(INSERT_ROWS_AMOUNT); - insertRowsLayout.addComponent(insertRowsAmount); - insertRowsLayout.addComponent(new Button("insert rows", - new Button.ClickListener() { - @Override - public void buttonClick(final ClickEvent event) { - final int offset = Integer.parseInt(insertRowsOffset - .getValue()); - final int amount = Integer.parseInt(insertRowsAmount - .getValue()); - grid.insertRows(offset, amount); - } - }) { - { - setId(INSERT_ROWS_BUTTON); - } - }); - addComponent(insertRowsLayout); - - final Layout removeRowsLayout = new HorizontalLayout(); - final TextField removeRowsOffset = new TextField(); - removeRowsOffset.setId(REMOVE_ROWS_OFFSET); - removeRowsLayout.addComponent(removeRowsOffset); - final TextField removeRowsAmount = new TextField(); - removeRowsAmount.setId(REMOVE_ROWS_AMOUNT); - removeRowsLayout.addComponent(removeRowsAmount); - removeRowsLayout.addComponent(new Button("remove rows", - new Button.ClickListener() { - @Override - public void buttonClick(final ClickEvent event) { - final int offset = Integer.parseInt(removeRowsOffset - .getValue()); - final int amount = Integer.parseInt(removeRowsAmount - .getValue()); - grid.removeRows(offset, amount); - } - }) { - { - setId(REMOVE_ROWS_BUTTON); - } - }); - addComponent(removeRowsLayout); - - final Layout insertColumnsLayout = new HorizontalLayout(); - final TextField insertColumnsOffset = new TextField(); - insertColumnsLayout.addComponent(insertColumnsOffset); - final TextField insertColumnsAmount = new TextField(); - insertColumnsLayout.addComponent(insertColumnsAmount); - insertColumnsLayout.addComponent(new Button("insert columns", - new Button.ClickListener() { - @Override - public void buttonClick(final ClickEvent event) { - final int offset = Integer.parseInt(insertColumnsOffset - .getValue()); - final int amount = Integer.parseInt(insertColumnsAmount - .getValue()); - grid.insertColumns(offset, amount); - } - })); - addComponent(insertColumnsLayout); - - final Layout removeColumnsLayout = new HorizontalLayout(); - final TextField removeColumnsOffset = new TextField(); - removeColumnsLayout.addComponent(removeColumnsOffset); - final TextField removeColumnsAmount = new TextField(); - removeColumnsLayout.addComponent(removeColumnsAmount); - removeColumnsLayout.addComponent(new Button("remove columns", - new Button.ClickListener() { - @Override - public void buttonClick(final ClickEvent event) { - final int offset = Integer.parseInt(removeColumnsOffset - .getValue()); - final int amount = Integer.parseInt(removeColumnsAmount - .getValue()); - grid.removeColumns(offset, amount); - } - })); - addComponent(removeColumnsLayout); - - final HorizontalLayout rowScroll = new HorizontalLayout(); - final NativeSelect destination = new NativeSelect(); - destination.setNullSelectionAllowed(false); - destination.addItem("any"); - destination.setValue("any"); - destination.addItem("start"); - destination.addItem("end"); - destination.addItem("middle"); - rowScroll.addComponent(destination); - final TextField rowIndex = new TextField(); - rowScroll.addComponent(rowIndex); - final TextField rowPadding = new TextField(); - rowScroll.addComponent(rowPadding); - rowScroll.addComponent(new Button("scroll to row", - new Button.ClickListener() { - @Override - public void buttonClick(final ClickEvent event) { - int index; - try { - index = Integer.parseInt(rowIndex.getValue()); - } catch (NumberFormatException e) { - index = 0; - } - - int padding; - try { - padding = Integer.parseInt(rowPadding.getValue()); - } catch (NumberFormatException e) { - padding = 0; - } - - grid.scrollToRow(index, - (String) destination.getValue(), padding); - } - })); - addComponent(rowScroll); - - final HorizontalLayout colScroll = new HorizontalLayout(); - final NativeSelect colDestination = new NativeSelect(); - colDestination.setNullSelectionAllowed(false); - colDestination.addItem("any"); - colDestination.setValue("any"); - colDestination.addItem("start"); - colDestination.addItem("end"); - colDestination.addItem("middle"); - colScroll.addComponent(colDestination); - final TextField colIndex = new TextField(); - colScroll.addComponent(colIndex); - final TextField colPadding = new TextField(); - colScroll.addComponent(colPadding); - colScroll.addComponent(new Button("scroll to column", - new Button.ClickListener() { - @Override - public void buttonClick(final ClickEvent event) { - int index; - try { - index = Integer.parseInt(colIndex.getValue()); - } catch (NumberFormatException e) { - index = 0; - } - - int padding; - try { - padding = Integer.parseInt(colPadding.getValue()); - } catch (NumberFormatException e) { - padding = 0; - } - - grid.scrollToColumn(index, - (String) colDestination.getValue(), padding); - } - })); - addComponent(colScroll); - - final TextField freezeCount = new TextField(); - freezeCount.setConverter(Integer.class); - freezeCount.setNullRepresentation(""); - addComponent(new HorizontalLayout(freezeCount, new Button( - "set frozen columns", new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - grid.setFrozenColumns(((Integer) freezeCount - .getConvertedValue()).intValue()); - freezeCount.setValue(null); - } - }))); - - addComponent(new Button("Resize randomly", new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - int width = random.nextInt(300) + 500; - int height = random.nextInt(300) + 200; - grid.setWidth(width + "px"); - grid.setHeight(height + "px"); - } - })); - - addComponent(new Button("Random headers count", - new Button.ClickListener() { - private int headers = 1; - - @Override - public void buttonClick(ClickEvent event) { - int diff = 0; - while (diff == 0) { - final int nextHeaders = random.nextInt(4); - diff = nextHeaders - headers; - headers = nextHeaders; - } - if (diff > 0) { - grid.insertHeaders(0, diff); - } else if (diff < 0) { - grid.removeHeaders(0, -diff); - } - } - })); - - addComponent(new Button("Random footers count", - new Button.ClickListener() { - private int footers = 1; - - @Override - public void buttonClick(ClickEvent event) { - int diff = 0; - while (diff == 0) { - final int nextFooters = random.nextInt(4); - diff = nextFooters - footers; - footers = nextFooters; - } - if (diff > 0) { - grid.insertFooters(0, diff); - } else if (diff < 0) { - grid.removeFooters(0, -diff); - } - } - })); - - final Layout resizeColumnsLayout = new HorizontalLayout(); - final TextField resizeColumnIndex = new TextField(); - resizeColumnsLayout.addComponent(resizeColumnIndex); - final TextField resizeColumnPx = new TextField(); - resizeColumnsLayout.addComponent(resizeColumnPx); - resizeColumnsLayout.addComponent(new Button("resize column", - new Button.ClickListener() { - @Override - public void buttonClick(final ClickEvent event) { - final int index = Integer.parseInt(resizeColumnIndex - .getValue()); - final int px = Integer.parseInt(resizeColumnPx - .getValue()); - grid.setColumnWidth(index, px); - } - })); - addComponent(resizeColumnsLayout); - - addComponent(new Button("Autoresize columns", - new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - grid.calculateColumnWidths(); - } - })); - - addComponent(new Button("Randomize row heights", - new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - grid.randomizeDefaultRowHeight(); - } - })); - } - - @Override - protected String getTestDescription() { - return null; - } - - @Override - protected Integer getTicketNumber() { - return null; - } - -} diff --git a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java b/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java deleted file mode 100644 index ba0b718f35..0000000000 --- a/uitest/src/com/vaadin/tests/components/grid/BasicEscalatorTest.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright 2000-2014 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.tests.components.grid; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.junit.Test; -import org.openqa.selenium.By; -import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.Keys; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; - -import com.vaadin.tests.annotations.TestCategory; -import com.vaadin.tests.tb3.MultiBrowserTest; - -@TestCategory("grid") -public class BasicEscalatorTest extends MultiBrowserTest { - - private static final int SLEEP = 300; - - private static final Pattern ROW_PATTERN = Pattern - .compile("Row (\\d+): \\d+,\\d+"); - - @Test - public void testInitialState() throws Exception { - openTestURL(); - - WebElement cell1 = getBodyRowCell(0, 0); - assertEquals("Top left body cell had unexpected content", "Row 0: 0,0", - cell1.getText()); - - WebElement cell2 = getBodyRowCell(15, 3); - assertEquals("Lower merged cell had unexpected content", "Cell: 3,15", - cell2.getText()); - } - - @Test - public void testScroll() throws Exception { - openTestURL(); - - /* - * let the DOM stabilize itself. TODO: remove once waitForVaadin - * supports lazy loaded components - */ - Thread.sleep(100); - - setScrollTop(getVerticalScrollbar(), 1000); - assertBodyCellWithContentIsFound("Row 50: 0,50"); - } - - @Test - public void testLastRow() throws Exception { - openTestURL(); - - /* - * let the DOM stabilize itself. TODO: remove once waitForVaadin - * supports lazy loaded components - */ - Thread.sleep(100); - - // scroll to bottom - setScrollTop(getVerticalScrollbar(), 100000000); - - /* - * this test does not test DOM reordering, therefore we don't rely on - * child indices - we simply seek by content. - */ - assertBodyCellWithContentIsFound("Row 99: 0,99"); - } - - @Test - public void testNormalRowHeight() throws Exception { - /* - * This is tested with screenshots instead of CSS queries, since some - * browsers report dimensions differently from each other, which is - * uninteresting for our purposes - */ - openTestURL(); - compareScreen("normalHeight"); - } - - @Test - public void testModifiedRowHeight() throws Exception { - /* - * This is tested with screenshots instead of CSS queries, since some - * browsers report dimensions differently from each other, which is - * uninteresting for our purposes - */ - openTestURLWithTheme("reindeer-tests"); - compareScreen("modifiedHeight"); - } - - private void assertBodyCellWithContentIsFound(String cellContent) { - String xpath = "//tbody/tr/td[.='" + cellContent + "']"; - try { - assertNotNull("received a null element with \"" + xpath + "\"", - getDriver().findElement(By.xpath(xpath))); - } catch (NoSuchElementException e) { - fail("Could not find '" + xpath + "'"); - } - } - - private WebElement getBodyRowCell(int row, int col) { - return getDriver().findElement( - By.xpath("//tbody/tr[@class='v-escalator-row'][" + (row + 1) - + "]/td[" + (col + 1) + "]")); - } - - private void openTestURLWithTheme(String themeName) { - String testUrl = getTestUrl(); - testUrl += (testUrl.contains("?")) ? "&" : "?"; - testUrl += "theme=" + themeName; - getDriver().get(testUrl); - } - - private Object executeScript(String script, WebElement element) { - @SuppressWarnings("hiding") - 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()); - } - } - - @Test - public void domIsInitiallySorted() throws Exception { - openTestURL(); - - final List rows = getBodyRows(); - assertTrue("no body rows found", !rows.isEmpty()); - for (int i = 0; i < rows.size(); i++) { - String text = rows.get(i).getText(); - String expected = "Row " + i; - assertTrue("Expected \"" + expected + "...\" but was " + text, - text.startsWith(expected)); - } - } - - @Test - public void domIsSortedAfterInsert() throws Exception { - openTestURL(); - - final int rowsToInsert = 5; - final int offset = 5; - insertRows(offset, rowsToInsert); - - final List rows = getBodyRows(); - int i = 0; - for (; i < offset + rowsToInsert; i++) { - final String expectedStart = "Row " + i; - final String text = rows.get(i).getText(); - assertTrue("Expected \"" + expectedStart + "...\" but was " + text, - text.startsWith(expectedStart)); - } - - for (; i < rows.size(); i++) { - final String expectedStart = "Row " + (i - rowsToInsert); - final String text = rows.get(i).getText(); - assertTrue("(post insert) Expected \"" + expectedStart - + "...\" but was " + text, text.startsWith(expectedStart)); - } - } - - @Test - public void domIsSortedAfterRemove() throws Exception { - openTestURL(); - - final int rowsToRemove = 5; - final int offset = 5; - removeRows(offset, rowsToRemove); - - final List rows = getBodyRows(); - int i = 0; - for (; i < offset; i++) { - final String expectedStart = "Row " + i; - final String text = rows.get(i).getText(); - assertTrue("Expected " + expectedStart + "... but was " + text, - text.startsWith(expectedStart)); - } - - /* - * We check only up to 10, since after that, the indices are again - * reset, because new rows have been generated. The row numbers that - * they are given depends on the widget size, and it's too fragile to - * rely on some special assumptions on that. - */ - for (; i < 10; i++) { - final String expectedStart = "Row " + (i + rowsToRemove); - final String text = rows.get(i).getText(); - assertTrue("(post remove) Expected " + expectedStart - + "... but was " + text, text.startsWith(expectedStart)); - } - } - - @Test - public void domIsSortedAfterScroll() throws Exception { - openTestURL(); - setScrollTop(getVerticalScrollbar(), 500); - - /* - * Let the DOM reorder itself. - * - * TODO TestBench currently doesn't know when Grid's DOM structure is - * stable. There are some plans regarding implementing support for this, - * so this test case can (should) be modified once that's implemented. - */ - sleep(SLEEP); - - List rows = getBodyRows(); - int firstRowNumber = parseFirstRowNumber(rows); - - for (int i = 0; i < rows.size(); i++) { - final String expectedStart = "Row " + (i + firstRowNumber); - final String text = rows.get(i).getText(); - assertTrue("(post remove) Expected " + expectedStart - + "... but was " + text, text.startsWith(expectedStart)); - } - } - - private static int parseFirstRowNumber(List rows) - throws NumberFormatException { - final WebElement firstRow = rows.get(0); - final String firstRowText = firstRow.getText(); - final Matcher matcher = ROW_PATTERN.matcher(firstRowText); - if (!matcher.find()) { - fail("could not find " + ROW_PATTERN.pattern() + " in \"" - + firstRowText + "\""); - } - final String number = matcher.group(1); - return Integer.parseInt(number); - } - - private void insertRows(final int offset, final int amount) { - final WebElement offsetInput = vaadinElementById(BasicEscalator.INSERT_ROWS_OFFSET); - offsetInput.sendKeys(String.valueOf(offset), Keys.RETURN); - - final WebElement amountInput = vaadinElementById(BasicEscalator.INSERT_ROWS_AMOUNT); - amountInput.sendKeys(String.valueOf(amount), Keys.RETURN); - - final WebElement button = vaadinElementById(BasicEscalator.INSERT_ROWS_BUTTON); - button.click(); - } - - private void removeRows(final int offset, final int amount) { - final WebElement offsetInput = vaadinElementById(BasicEscalator.REMOVE_ROWS_OFFSET); - offsetInput.sendKeys(String.valueOf(offset), Keys.RETURN); - - final WebElement amountInput = vaadinElementById(BasicEscalator.REMOVE_ROWS_AMOUNT); - amountInput.sendKeys(String.valueOf(amount), Keys.RETURN); - - final WebElement button = vaadinElementById(BasicEscalator.REMOVE_ROWS_BUTTON); - button.click(); - } - - private void setScrollTop(WebElement element, long px) { - executeScript("arguments[0].scrollTop = " + px, element); - } - - private List getBodyRows() { - return getDriver().findElements(By.xpath("//tbody/tr/td[1]")); - } - - private WebElement getVerticalScrollbar() { - return getDriver().findElement( - By.xpath("//div[" - + "contains(@class, 'v-escalator-scroller-vertical')" - + "]")); - } -} 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/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..c15815bf0d --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java @@ -0,0 +1,506 @@ +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.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 { + + 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 cellsToAttach) { + // noop + } + + @Override + public void postAttach(Row row, Iterable attachedCells) { + // noop + } + + @Override + public void preDetach(Row row, Iterable cellsToDetach) { + // noop + } + + @Override + public void postDetach(Row row, Iterable detachedCells) { + // noop + } + } + + private class Data { + private int columnCounter = 0; + private int rowCounter = 0; + private final List columns = new ArrayList(); + private final List rows = new ArrayList(); + + @SuppressWarnings("boxing") + public void insertRows(final int offset, final int amount) { + final List newRows = new ArrayList(); + 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 newColumns = new ArrayList(); + 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 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 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 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); + } + } + } + + private final Escalator escalator; + private final Data data = new Data(); + private final HTML debugLabel = new HTML(); + + private enum Colspan { + NONE, NORMAL, CRAZY; + } + + private Colspan colspan = Colspan.NONE; + + public EscalatorBasicClientFeaturesWidget() { + super(new EscalatorProxy()); + escalator = getTestedWidget(); + ((EscalatorProxy) escalator).setDebugLabel(debugLabel); + addNorth(debugLabel, 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..bf4e1975b2 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java @@ -0,0 +1,239 @@ +/* + * 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.Duration; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.TableRowElement; +import com.google.gwt.user.client.ui.HTML; +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; + +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); + log("removeColumns " + index + ", " + numberOfColumns); + updateDebugLabel(); + } + + @Override + public void insertColumns(int index, int numberOfColumns) + throws IndexOutOfBoundsException, IllegalArgumentException { + columnConfiguration.insertColumns(index, numberOfColumns); + log("insertColumns " + index + ", " + numberOfColumns); + 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); + log(rowContainer.getClass().getSimpleName() + " removeRows " + + index + ", " + numberOfRows); + updateDebugLabel(); + } + + @Override + public void insertRows(int index, int numberOfRows) + throws IndexOutOfBoundsException, IllegalArgumentException { + rowContainer.insertRows(index, numberOfRows); + log(rowContainer.getClass().getSimpleName() + " insertRows " + + index + ", " + numberOfRows); + updateDebugLabel(); + } + + @Override + public void refreshRows(int index, int numberOfRows) + throws IndexOutOfBoundsException, IllegalArgumentException { + rowContainer.refreshRows(index, numberOfRows); + 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 static final int MAX_LOG = 9; + + private RowContainer headerProxy = null; + private RowContainer bodyProxy = null; + private RowContainer footerProxy = null; + private ColumnConfiguration columnProxy = null; + private HTML debugLabel; + private List logs = new ArrayList(); + + @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 setDebugLabel(HTML debugLabel) { + this.debugLabel = debugLabel; + updateDebugLabel(); + } + + public void updateDebugLabel() { + int headers = super.getHeader().getRowCount(); + int bodys = super.getBody().getRowCount(); + int footers = super.getFooter().getRowCount(); + int columns = super.getColumnConfiguration().getColumnCount(); + + while (logs.size() > MAX_LOG) { + logs.remove(0); + } + + String logString = "
"; + for (String log : logs) { + logString += log + "
"; + } + + debugLabel.setHTML( // + "Columns: " + columns + "
" + // + "Header rows: " + headers + "
" + // + "Body rows:" + bodys + "
" + // + "Footer rows:" + footers + "
" + // + logString); + } + + public void log(String string) { + logs.add((Duration.currentTimeMillis() % 10000) + ": " + string); + } +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridClientRpc.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridClientRpc.java deleted file mode 100644 index ae2799d228..0000000000 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridClientRpc.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2000-2013 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; - -public interface TestGridClientRpc extends ClientRpc { - void insertRows(int offset, int amount); - - void removeRows(int offset, int amount); - - void insertColumns(int offset, int amount); - - void removeColumns(int offset, int amount); - - void scrollToRow(int index, String destination, int padding); - - void scrollToColumn(int index, String destination, int padding); - - void setFrozenColumns(int frozenColumns); - - void insertHeaders(int index, int amount); - - void removeHeaders(int index, int amount); - - void insertFooters(int index, int amount); - - void removeFooters(int index, int amount); - - void setColumnWidth(int index, int px); - - void calculateColumnWidths(); - - void randomRowHeight(); -} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java deleted file mode 100644 index 6dbff5ca66..0000000000 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridConnector.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2000-2013 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.user.client.Random; -import com.vaadin.client.ui.AbstractComponentConnector; -import com.vaadin.shared.ui.Connect; -import com.vaadin.shared.ui.grid.ScrollDestination; -import com.vaadin.tests.widgetset.server.grid.TestGrid; - -/** - * @since - * @author Vaadin Ltd - */ -@Connect(TestGrid.class) -public class TestGridConnector extends AbstractComponentConnector { - @Override - protected void init() { - super.init(); - registerRpc(TestGridClientRpc.class, new TestGridClientRpc() { - @Override - public void insertRows(int offset, int amount) { - getWidget().insertRows(offset, amount); - } - - @Override - public void removeRows(int offset, int amount) { - getWidget().removeRows(offset, amount); - } - - @Override - public void removeColumns(int offset, int amount) { - getWidget().removeColumns(offset, amount); - } - - @Override - public void insertColumns(int offset, int amount) { - getWidget().insertColumns(offset, amount); - } - - @Override - public void scrollToRow(int index, String destination, int padding) { - getWidget().scrollToRow(index, getDestination(destination), - padding); - } - - @Override - public void scrollToColumn(int index, String destination, - int padding) { - getWidget().scrollToColumn(index, getDestination(destination), - padding); - } - - private ScrollDestination getDestination(String destination) { - final ScrollDestination d; - if (destination.equals("start")) { - d = ScrollDestination.START; - } else if (destination.equals("middle")) { - d = ScrollDestination.MIDDLE; - } else if (destination.equals("end")) { - d = ScrollDestination.END; - } else { - d = ScrollDestination.ANY; - } - return d; - } - - @Override - public void setFrozenColumns(int frozenColumns) { - getWidget().getColumnConfiguration().setFrozenColumnCount( - frozenColumns); - } - - @Override - public void insertHeaders(int index, int amount) { - getWidget().getHeader().insertRows(index, amount); - } - - @Override - public void removeHeaders(int index, int amount) { - getWidget().getHeader().removeRows(index, amount); - } - - @Override - public void insertFooters(int index, int amount) { - getWidget().getFooter().insertRows(index, amount); - } - - @Override - public void removeFooters(int index, int amount) { - getWidget().getFooter().removeRows(index, amount); - } - - @Override - public void setColumnWidth(int index, int px) { - getWidget().getColumnConfiguration().setColumnWidth(index, px); - } - - @Override - public void calculateColumnWidths() { - getWidget().calculateColumnWidths(); - } - - @Override - public void randomRowHeight() { - getWidget().getHeader().setDefaultRowHeight( - Random.nextInt(20) + 20); - getWidget().getBody().setDefaultRowHeight( - Random.nextInt(20) + 20); - getWidget().getFooter().setDefaultRowHeight( - Random.nextInt(20) + 20); - } - }); - } - - @Override - public VTestGrid getWidget() { - return (VTestGrid) super.getWidget(); - } - - @Override - public TestGridState getState() { - return (TestGridState) super.getState(); - } -} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java deleted file mode 100644 index ecbc59552b..0000000000 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/TestGridState.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2000-2013 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.AbstractComponentState; - -/** - * @since - * @author Vaadin Ltd - */ -public class TestGridState extends AbstractComponentState { - public static final String DEFAULT_HEIGHT = "400.0px"; - - /* TODO: this should be "100%" before setting final. */ - public static final String DEFAULT_WIDTH = "800.0px"; -} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java deleted file mode 100644 index fbce00fc11..0000000000 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/VTestGrid.java +++ /dev/null @@ -1,249 +0,0 @@ -package com.vaadin.tests.widgetset.client.grid; - -import java.util.ArrayList; -import java.util.List; - -import com.google.gwt.user.client.Window.Location; -import com.google.gwt.user.client.ui.Composite; -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.FlyweightCell; -import com.vaadin.client.ui.grid.Row; -import com.vaadin.client.ui.grid.RowContainer; -import com.vaadin.shared.ui.grid.ScrollDestination; - -public class VTestGrid extends Composite { - - private static abstract class TestEscalatorUpdater implements - EscalatorUpdater { - - @Override - public void preAttach(Row row, Iterable cellsToAttach) { - } - - @Override - public void postAttach(Row row, Iterable attachedCells) { - } - - @Override - public void preDetach(Row row, Iterable cellsToDetach) { - } - - @Override - public void postDetach(Row row, Iterable detachedCells) { - } - } - - private static class Data { - private int columnCounter = 0; - private int rowCounter = 0; - private final List columns = new ArrayList(); - private final List rows = new ArrayList(); - - @SuppressWarnings("boxing") - public void insertRows(final int offset, final int amount) { - final List newRows = new ArrayList(); - 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 newColumns = new ArrayList(); - 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 cellsToUpdate) { - for (final FlyweightCell cell : cellsToUpdate) { - if (cell.getColumn() % 3 == 0) { - cell.setColSpan(2); - } - - final Integer columnName = columns - .get(cell.getColumn()); - cell.getElement().setInnerText("Header " + columnName); - } - } - }; - } - - public EscalatorUpdater createFooterUpdater() { - return new TestEscalatorUpdater() { - @Override - public void update(final Row row, - final Iterable cellsToUpdate) { - for (final FlyweightCell cell : cellsToUpdate) { - if (cell.getColumn() % 3 == 1) { - cell.setColSpan(2); - } - - final Integer columnName = columns - .get(cell.getColumn()); - cell.getElement().setInnerText("Footer " + columnName); - } - } - }; - } - - public EscalatorUpdater createBodyUpdater() { - return new TestEscalatorUpdater() { - private int i = 0; - - 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 (shouldRenderPretty()) { - cellInfo += " (" + i + ")"; - } - - if (cell.getColumn() > 0) { - cell.getElement().setInnerText("Cell: " + cellInfo); - } else { - cell.getElement().setInnerText( - "Row " + cell.getRow() + ": " + cellInfo); - } - - if (cell.getColumn() % 3 == cell.getRow() % 3) { - cell.setColSpan(3); - } - - if (shouldRenderPretty()) { - final double c = i * .1; - final int r = (int) ((Math.cos(c) + 1) * 128); - final int g = (int) ((Math.cos(c / Math.PI) + 1) * 128); - final int b = (int) ((Math.cos(c / (Math.PI * 2)) + 1) * 128); - cell.getElement() - .getStyle() - .setBackgroundColor( - "rgb(" + r + "," + g + "," + b + ")"); - if ((r * .8 + g * 1.3 + b * .9) / 3 < 127) { - cell.getElement().getStyle().setColor("white"); - } else { - cell.getElement().getStyle().clearColor(); - } - } - - i++; - } - - private boolean shouldRenderPretty() { - return Location.getQueryString().contains("pretty"); - } - - @Override - public void update(final Row row, - final Iterable 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); - } - } - } - - private final Escalator escalator = new Escalator(); - private final Data data = new Data(); - - public VTestGrid() { - initWidget(escalator); - final RowContainer header = escalator.getHeader(); - header.setEscalatorUpdater(data.createHeaderUpdater()); - header.insertRows(0, 1); - - final RowContainer footer = escalator.getFooter(); - footer.setEscalatorUpdater(data.createFooterUpdater()); - footer.insertRows(0, 1); - - escalator.getBody().setEscalatorUpdater(data.createBodyUpdater()); - - insertRows(0, 100); - insertColumns(0, 10); - - setWidth(TestGridState.DEFAULT_WIDTH); - setHeight(TestGridState.DEFAULT_HEIGHT); - - } - - public void insertRows(final int offset, final int number) { - data.insertRows(offset, number); - escalator.getBody().insertRows(offset, number); - } - - public void insertColumns(final int offset, final int number) { - data.insertColumns(offset, number); - escalator.getColumnConfiguration().insertColumns(offset, number); - } - - public ColumnConfiguration getColumnConfiguration() { - return escalator.getColumnConfiguration(); - } - - public void scrollToRow(final int index, - final ScrollDestination destination, final int padding) { - escalator.scrollToRow(index, destination, padding); - } - - public void scrollToColumn(final int index, - final ScrollDestination destination, final int padding) { - escalator.scrollToColumn(index, destination, padding); - } - - public void removeRows(final int offset, final int amount) { - data.removeRows(offset, amount); - escalator.getBody().removeRows(offset, amount); - } - - public void removeColumns(final int offset, final int amount) { - data.removeColumns(offset, amount); - escalator.getColumnConfiguration().removeColumns(offset, amount); - } - - @Override - public void setWidth(String width) { - escalator.setWidth(width); - } - - @Override - public void setHeight(String height) { - escalator.setHeight(height); - } - - public RowContainer getHeader() { - return escalator.getHeader(); - } - - public RowContainer getBody() { - return escalator.getBody(); - } - - public RowContainer getFooter() { - return escalator.getFooter(); - } - - public void calculateColumnWidths() { - escalator.calculateColumnWidths(); - } -} diff --git a/uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java b/uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java deleted file mode 100644 index 0dbb60359d..0000000000 --- a/uitest/src/com/vaadin/tests/widgetset/server/grid/TestGrid.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2000-2013 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 com.vaadin.tests.widgetset.client.grid.TestGridClientRpc; -import com.vaadin.tests.widgetset.client.grid.TestGridState; -import com.vaadin.ui.AbstractComponent; - -/** - * @since - * @author Vaadin Ltd - */ -public class TestGrid extends AbstractComponent { - public TestGrid() { - setWidth(TestGridState.DEFAULT_WIDTH); - setHeight(TestGridState.DEFAULT_HEIGHT); - } - - @Override - protected TestGridState getState() { - return (TestGridState) super.getState(); - } - - public void insertRows(int offset, int amount) { - rpc().insertRows(offset, amount); - } - - public void removeRows(int offset, int amount) { - rpc().removeRows(offset, amount); - } - - public void insertColumns(int offset, int amount) { - rpc().insertColumns(offset, amount); - } - - public void removeColumns(int offset, int amount) { - rpc().removeColumns(offset, amount); - } - - private TestGridClientRpc rpc() { - return getRpcProxy(TestGridClientRpc.class); - } - - public void scrollToRow(int index, String destination, int padding) { - rpc().scrollToRow(index, destination, padding); - } - - public void scrollToColumn(int index, String destination, int padding) { - rpc().scrollToColumn(index, destination, padding); - } - - public void setFrozenColumns(int frozenColumns) { - rpc().setFrozenColumns(frozenColumns); - } - - public void insertHeaders(int index, int amount) { - rpc().insertHeaders(index, amount); - } - - public void removeHeaders(int index, int amount) { - rpc().removeHeaders(index, amount); - } - - public void insertFooters(int index, int amount) { - rpc().insertFooters(index, amount); - } - - public void removeFooters(int index, int amount) { - rpc().removeFooters(index, amount); - } - - public void setColumnWidth(int index, int px) { - rpc().setColumnWidth(index, px); - } - - public void calculateColumnWidths() { - rpc().calculateColumnWidths(); - } - - public void randomizeDefaultRowHeight() { - rpc().randomRowHeight(); - } -} -- cgit v1.2.3 From b6fa10dc8568ba9599535d143a9b6470620e84fa Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Wed, 27 Aug 2014 18:01:49 +0300 Subject: Adds frozen feature to GridBasicClientFeaturesWidget (#13334) Change-Id: I6142c8a6af8248c4568b836c3e62531167f30439 --- .../com/vaadin/tests/components/grid/GridElement.java | 5 +++++ .../client/GridClientColumnPropertiesTest.java | 18 ++++++++++++++++++ .../client/grid/GridBasicClientFeaturesWidget.java | 11 +++++++++++ 3 files changed, 34 insertions(+) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/GridElement.java b/uitest/src/com/vaadin/tests/components/grid/GridElement.java index bd8cad45c6..27c552340a 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridElement.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridElement.java @@ -40,6 +40,7 @@ public class GridElement extends AbstractComponentElement { 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); @@ -48,6 +49,10 @@ public class GridElement extends AbstractComponentElement { 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 { 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 index ece9fdf7d7..ea46ee24a5 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientColumnPropertiesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientColumnPropertiesTest.java @@ -16,6 +16,8 @@ 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; @@ -56,4 +58,20 @@ public class GridClientColumnPropertiesTest extends GridBasicClientFeaturesTest 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/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index a8fa6d1a08..9cf56439d8 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -357,6 +357,17 @@ public class GridBasicClientFeaturesWidget extends !grid.getColumn(index).isSortable()); } }, "Component", "Columns", "Column " + i); + addMenuCommand("Frozen", new ScheduledCommand() { + @Override + public void execute() { + GridColumn> column = grid.getColumn(index); + if (column.equals(grid.getLastFrozenColumn())) { + grid.setLastFrozenColumn(null); + } else { + grid.setLastFrozenColumn(column); + } + } + }, "Component", "Columns", "Column " + i); addMenuCommand("auto", new ScheduledCommand() { @Override -- cgit v1.2.3 From 19a66bd5327a3c5b6e96f7741417181d2884cfd8 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Thu, 4 Sep 2014 10:33:48 +0300 Subject: Escalator test base class (#13334) Change-Id: Ie3670e4d937b437dc11098746fcd4571e850355f --- .../EscalatorBasicClientFeaturesTest.java | 128 +++++++++++++++++++++ .../grid/EscalatorBasicClientFeaturesWidget.java | 1 + .../widgetset/client/grid/EscalatorProxy.java | 4 +- 3 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java (limited to 'uitest/src') 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..745802a04f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java @@ -0,0 +1,128 @@ +/* + * 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.assertTrue; + +import org.openqa.selenium.By; +import org.openqa.selenium.Dimension; +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 HEADER_ROWS = "Header Rows"; + protected static final String BODY_ROWS = "Body Rows"; + protected static final String FOOTER_ROWS = "Footer Rows"; + + @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) { + WebElement log = getDriver().findElement(By.cssSelector("#log")); + assertTrue("log did not contain: " + substring, + log.getText().contains(substring)); + } +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java index c15815bf0d..068902ef0f 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java @@ -178,6 +178,7 @@ public class EscalatorBasicClientFeaturesWidget extends escalator = getTestedWidget(); ((EscalatorProxy) escalator).setDebugLabel(debugLabel); addNorth(debugLabel, 200); + debugLabel.getElement().setId("log"); final RowContainer header = escalator.getHeader(); header.setEscalatorUpdater(data.createHeaderUpdater()); diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java index bf4e1975b2..5655684b82 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java @@ -228,8 +228,8 @@ public class EscalatorProxy extends Escalator { debugLabel.setHTML( // "Columns: " + columns + "
" + // "Header rows: " + headers + "
" + // - "Body rows:" + bodys + "
" + // - "Footer rows:" + footers + "
" + // + "Body rows: " + bodys + "
" + // + "Footer rows: " + footers + "
" + // logString); } -- cgit v1.2.3 From 224d2f5fe7af5ec235047357129eb99bdaa17bd5 Mon Sep 17 00:00:00 2001 From: Patrik Lindström Date: Wed, 3 Sep 2014 14:50:47 +0300 Subject: Fix and unify multi-column sorting behavior (#13334) Change-Id: Idc5b66395eb132a3a0a177593f5d91a165a925de --- client/src/com/vaadin/client/ui/grid/Grid.java | 185 ++++++++++----------- .../grid/basicfeatures/server/GridSortingTest.java | 11 +- 2 files changed, 97 insertions(+), 99 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 478e7b4a9d..cd9b615c4b 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -597,80 +597,107 @@ public class Grid extends Composite implements } /** - * Class for sorting at a later time - */ - private class LazySorter extends Timer { + * Helper class for performing sorting through the user interface. Controls + * the sort() method, reporting USER as the event originator. This is a + * completely internal class, and is, as such, safe to re-name should a more + * descriptive name come to mind. + */ + private final class UserSorter { + + private final Timer timer; + private Cell scheduledCell; + private boolean scheduledMultisort; + + private UserSorter() { + timer = new Timer() { + @Override + public void run() { + UserSorter.this.sort(scheduledCell, scheduledMultisort); + } + }; + } - private Cell cell; + /** + * Toggle sorting for a cell. If the multisort parameter is set to true, + * the cell's sort order is modified as a natural part of a multi-sort + * chain. If false, the sorting order is set to ASCENDING for that + * cell's column. If that column was already the only sorted column in + * the Grid, the sort direction is flipped. + * + * @param cell + * a valid cell reference + * @param multisort + * whether the sort command should act as a multi-sort stack + * or not + */ + public void sort(Cell cell, boolean multisort) { - private boolean multisort; + final GridColumn column = getColumnFromVisibleIndex(cell + .getColumn()); + final SortOrder so = getSortOrder(column); - @Override - public void run() { - SortOrder sortingOrder = getSortOrder(getColumnFromVisibleIndex(cell - .getColumn())); - if (sortingOrder == null) { - /* - * No previous sorting, sort Ascending - */ - sort(cell, SortDirection.ASCENDING, multisort); + if (multisort) { + + // If the sort order exists, replace existing value with its + // opposite + if (so != null) { + final int idx = sortOrder.indexOf(so); + sortOrder.set(idx, so.getOpposite()); + } else { + // If it doesn't, just add a new sort order to the end of + // the list + sortOrder.add(new SortOrder(column)); + } } else { - // Toggle sorting - SortDirection direction = sortingOrder.getDirection(); - if (direction == SortDirection.ASCENDING) { - sort(cell, SortDirection.DESCENDING, multisort); + + // Since we're doing single column sorting, first clear the + // list. Then, if the sort order existed, add its opposite, + // otherwise just add a new sort value + + int items = sortOrder.size(); + sortOrder.clear(); + if (so != null && items == 1) { + sortOrder.add(so.getOpposite()); } else { - sort(cell, SortDirection.ASCENDING, multisort); + sortOrder.add(new SortOrder(column)); } } + + // sortOrder has been changed; tell the Grid to re-sort itself by + // user request. + Grid.this.sort(SortEventOriginator.USER); } /** - * Set the cell reference to the primary cell that sorting should be - * done for. - * - * @param cell + * Perform a sort after a delay. * + * @param delay + * delay, in milliseconds */ - public void setCellReference(Cell cell) { - this.cell = cell; + public void sortAfterDelay(int delay, Cell cell, boolean multisort) { + scheduledCell = cell; + scheduledMultisort = multisort; + timer.schedule(delay); } /** - * Is multiple column sorting is enabled/disabled + * Check if a delayed sort command has been issued but not yet carried + * out. * - * @param multisort - * true if multiple column sorting is enabled + * @return a boolean value */ - public void setMultisort(boolean multisort) { - this.multisort = multisort; + public boolean isDelayedSortScheduled() { + return timer.isRunning(); } /** - * Sorts the column in a direction + * Cancel a scheduled sort. */ - private void sort(Cell cell, SortDirection direction, boolean multisort) { - TableCellElement th = TableCellElement.as(cell.getElement()); - - // Apply primary sorting on clicked column - GridColumn columnInstance = getColumnFromVisibleIndex(cell - .getColumn()); - Sort sorting = Sort.by(columnInstance, direction); - - // Re-apply old sorting to the sort order - if (multisort) { - for (SortOrder order : getSortOrder()) { - if (order.getColumn() != columnInstance) { - sorting = sorting.then(order.getColumn(), - order.getDirection()); - } - } - } - - // Perform sorting; indicate originator as user - Grid.this.setSortOrder(sorting.build(), SortEventOriginator.USER); + public void cancelDelayedSort() { + timer.cancel(); } + } /** @@ -726,7 +753,7 @@ public class Grid extends Composite implements protected final ActiveCellHandler activeCellHandler; - private final LazySorter lazySorter = new LazySorter(); + private final UserSorter sorter = new UserSorter(); private final EditorRow editorRow = GWT.create(EditorRow.class); @@ -1327,39 +1354,7 @@ public class Grid extends Composite implements return; } - final Cell cell = event.getActiveCell(); - final GridColumn column = columns.get(cell.getColumn()); - - // If SHIFT is down, we modify multi-sorting order - if (event.isShiftKeyDown() && sortOrder != null) { - - final SortOrder so = getSortOrder(column); - - if (so != null) { - // Flip sort direction in-place - final int idx = sortOrder.indexOf(so); - sortOrder.set(idx, so.getOpposite()); - } else { - // Add a new sort rule to the end of the list - sortOrder.add(new SortOrder(column)); - } - - } else { - if (sortOrder.size() == 1 - && sortOrder.get(0).getColumn() == column) { - - // Reverse the sort order and re-sort - sortOrder.set(0, sortOrder.get(0).getOpposite()); - } else { - - // Manually re-set the sorting order - sortOrder.clear(); - sortOrder.add(new SortOrder(column)); - } - } - - // We've modified the sort order, re-sort it now. - setSortOrder(sortOrder, SortEventOriginator.USER); + sorter.sort(event.getActiveCell(), event.isShiftKeyDown()); } }); } @@ -2240,9 +2235,7 @@ public class Grid extends Composite implements rowEventTouchStartingPoint = new Point(touch.getClientX(), touch.getClientY()); - lazySorter.setCellReference(cell); - lazySorter.setMultisort(true); - lazySorter.schedule(GridConstants.LONG_TAP_DELAY); + sorter.sortAfterDelay(GridConstants.LONG_TAP_DELAY, cell, true); return true; @@ -2263,7 +2256,7 @@ public class Grid extends Composite implements // starting point if (diffX > GridConstants.LONG_TAP_THRESHOLD || diffY > GridConstants.LONG_TAP_THRESHOLD) { - lazySorter.cancel(); + sorter.cancelDelayedSort(); } return true; @@ -2273,11 +2266,10 @@ public class Grid extends Composite implements return false; } - if (lazySorter.isRunning()) { + if (sorter.isDelayedSortScheduled()) { // Not a long tap yet, perform single sort - lazySorter.cancel(); - lazySorter.setMultisort(false); - lazySorter.run(); + sorter.cancelDelayedSort(); + sorter.sort(cell, false); } return true; @@ -2287,14 +2279,13 @@ public class Grid extends Composite implements return false; } - lazySorter.cancel(); + sorter.cancelDelayedSort(); return true; } else if (BrowserEvents.CLICK.equals(event.getType())) { - lazySorter.setCellReference(cell); - lazySorter.setMultisort(event.getShiftKey()); - lazySorter.run(); + + sorter.sort(cell, event.getShiftKey()); // Click events should go onward to active cell logic return false; 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 index 74a5c6ed95..acc5bfe51a 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSortingTest.java @@ -208,7 +208,7 @@ public class GridSortingTest extends GridBasicFeaturesTest { } @Test - public void testKeyboardMultiColumnSorting() throws InterruptedException { + public void testKeyboardSorting() { openTestURL(); // @@ -254,10 +254,17 @@ public class GridSortingTest extends GridBasicFeaturesTest { // Move back to the third column sendKeys(Keys.RIGHT); - // Reset sorting to third column, ASCENDING + // 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) { -- cgit v1.2.3 From 69798ea10a289afe384617def233992eb80c9fda Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Mon, 25 Aug 2014 11:02:09 +0300 Subject: Implement client-side editor row widget binding (#13334) Change-Id: I898d89cecc2d1c552a3cc32461d612d55d1babd7 --- .../src/com/vaadin/client/ui/grid/EditorRow.java | 62 ++++++++++++++++++++-- .../vaadin/client/ui/grid/EditorRowHandler.java | 38 +++++++++++++ client/src/com/vaadin/client/ui/grid/Grid.java | 6 +-- .../com/vaadin/client/ui/grid/GridConnector.java | 32 ++++++++++- .../com/vaadin/shared/ui/grid/GridColumnState.java | 9 ++++ .../client/GridEditorRowClientTest.java | 21 ++++++++ .../client/grid/GridBasicClientFeaturesWidget.java | 11 ++++ 7 files changed, 171 insertions(+), 8 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/grid/EditorRowHandler.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/EditorRow.java b/client/src/com/vaadin/client/ui/grid/EditorRow.java index c57ae26ff3..9399898473 100644 --- a/client/src/com/vaadin/client/ui/grid/EditorRow.java +++ b/client/src/com/vaadin/client/ui/grid/EditorRow.java @@ -15,6 +15,9 @@ */ package com.vaadin.client.ui.grid; +import java.util.ArrayList; +import java.util.List; + import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style; @@ -23,6 +26,7 @@ import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.dom.client.TableRowElement; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.grid.Escalator.AbstractRowContainer; import com.vaadin.client.ui.grid.ScrollbarBundle.Direction; import com.vaadin.shared.ui.grid.ScrollDestination; @@ -43,9 +47,13 @@ public class EditorRow { INACTIVE, ACTIVATING, ACTIVE, COMMITTING } + private Grid grid; + + private EditorRowHandler handler; + private DivElement editorOverlay = DivElement.as(DOM.createDiv()); - private Grid grid; + private List editorWidgets = new ArrayList(); private boolean enabled = false; private State state = State.INACTIVE; @@ -110,6 +118,34 @@ public class EditorRow { state = State.INACTIVE; } + /** + * Returns the handler responsible for binding data and editor widgets to + * this editor row. + * + * @return the editor row handler or null if not set + */ + public EditorRowHandler getHandler() { + return handler; + } + + /** + * Sets the handler responsible for binding data and editor widgets to this + * editor row. + * + * @param rowHandler + * the new editor row handler + * + * @throws IllegalStateException + * if this editor row is currently in edit mode + */ + public void setHandler(EditorRowHandler rowHandler) { + if (state != State.INACTIVE) { + throw new IllegalStateException( + "Cannot set EditorRowHandler: EditorRow is currently in edit mode"); + } + this.handler = rowHandler; + } + public boolean isEnabled() { return enabled; } @@ -122,11 +158,16 @@ public class EditorRow { * * @throws IllegalStateException * if in edit mode and trying to disable + * @throws IllegalStateException + * if the editor row handler is not set */ public void setEnabled(boolean enabled) { if (enabled == false && state != State.INACTIVE) { throw new IllegalStateException( "Cannot disable: EditorRow is in edit mode"); + } else if (enabled == true && getHandler() == null) { + throw new IllegalStateException( + "Cannot enable: EditorRowHandler not set"); } this.enabled = enabled; } @@ -184,15 +225,30 @@ public class EditorRow { setBounds(editorOverlay, tr.getOffsetLeft(), rowTop + bodyTop - wrapperTop, tr.getOffsetWidth(), tr.getOffsetHeight()); + tableWrapper.appendChild(editorOverlay); + for (int i = 0; i < tr.getCells().getLength(); i++) { Element cell = createCell(tr.getCells().getItem(i)); + editorOverlay.appendChild(cell); - } - tableWrapper.appendChild(editorOverlay); + Widget editor = getHandler().getWidget( + grid.getColumnFromVisibleIndex(i)); + if (editor != null) { + editorWidgets.add(editor); + cell.appendChild(editor.getElement()); + Grid.setParent(editor, grid); + } + } } protected void hideOverlay() { + for (Widget w : editorWidgets) { + Grid.setParent(w, null); + } + editorWidgets.clear(); + + editorOverlay.removeAllChildren(); editorOverlay.removeFromParent(); } diff --git a/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java b/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java new file mode 100644 index 0000000000..43c43c67f6 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui.grid; + +import com.google.gwt.user.client.ui.Widget; + +/** + * An interface for binding widgets and data to the editor row. + * + * @since + * @author Vaadin Ltd + */ +public interface EditorRowHandler { + + /** + * Returns the widget instance that is used to edit the values in the given + * column. A null return value means the column is not editable. + * + * @param column + * the column whose values should be edited + * @return the editor widget for the column or null if the column is not + * editable + */ + public Widget getWidget(GridColumn column); +} diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 2b0bbc9f05..a667bfa8dd 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -1571,7 +1571,7 @@ public class Grid extends Composite implements } } - private int findVisibleColumnIndex(GridColumn column) { + protected int findVisibleColumnIndex(GridColumn column) { int idx = 0; for (GridColumn c : columns) { if (c == column) { @@ -1583,7 +1583,7 @@ public class Grid extends Composite implements return -1; } - private GridColumn getColumnFromVisibleIndex(int index) { + protected GridColumn getColumnFromVisibleIndex(int index) { int idx = -1; for (GridColumn c : columns) { if (c.isVisible()) { @@ -2436,7 +2436,7 @@ public class Grid extends Composite implements * @param parent * The parent to set */ - private static native final void setParent(Widget widget, Widget parent) + static native final void setParent(Widget widget, Widget parent) /*-{ widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent); }-*/; diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index a06e1df802..8ff467cfd5 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -30,12 +30,14 @@ import java.util.logging.Logger; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONValue; +import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.data.DataSource.RowHandle; import com.vaadin.client.data.RpcDataSourceConnector.RpcDataSource; +import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.AbstractHasComponentsConnector; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; @@ -87,6 +89,8 @@ public class GridConnector extends AbstractHasComponentsConnector { private AbstractRendererConnector rendererConnector; + private AbstractFieldConnector editorConnector; + public CustomGridColumn(String id, AbstractRendererConnector rendererConnector) { super(rendererConnector.getRenderer()); @@ -116,6 +120,14 @@ public class GridConnector extends AbstractHasComponentsConnector { return rendererConnector; } + private AbstractFieldConnector getEditorConnector() { + return editorConnector; + } + + private void setEditorConnector(AbstractFieldConnector editorConnector) { + this.editorConnector = editorConnector; + } + private int resolveCurrentIndexFromState() { List columns = getState().columns; int numColumns = columns.size(); @@ -128,6 +140,18 @@ public class GridConnector extends AbstractHasComponentsConnector { } } + private class CustomEditorRowHandler implements + EditorRowHandler { + + @Override + public Widget getWidget(GridColumn column) { + assert column != null; + AbstractFieldConnector c = ((CustomGridColumn) column) + .getEditorConnector(); + return c != null ? c.getWidget() : null; + } + } + /** * Maps a generated column id to a grid column instance */ @@ -229,6 +253,8 @@ public class GridConnector extends AbstractHasComponentsConnector { } } }); + + getWidget().getEditorRow().setHandler(new CustomEditorRowHandler()); } @Override @@ -362,13 +388,14 @@ public class GridConnector extends AbstractHasComponentsConnector { getWidgetColumnIndex(columnIndex)); GridColumnState columnState = getState().columns.get(columnIndex); - updateColumnFromState(column, columnState); assert column instanceof CustomGridColumn : "column at index " + columnIndex + " is not a " + CustomGridColumn.class.getSimpleName() + ", but a " + column.getClass().getSimpleName(); + updateColumnFromState((CustomGridColumn) column, columnState); + if (columnState.rendererConnector != ((CustomGridColumn) column) .getRendererConnector()) { throw new UnsupportedOperationException( @@ -432,11 +459,12 @@ public class GridConnector extends AbstractHasComponentsConnector { * @param state * The state to get the data from */ - private static void updateColumnFromState(GridColumn column, + private static void updateColumnFromState(CustomGridColumn column, GridColumnState state) { column.setVisible(state.visible); column.setWidth(state.width); column.setSortable(state.sortable); + column.setEditorConnector((AbstractFieldConnector) state.editorConnector); } /** diff --git a/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java b/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java index b73e7cffd5..d9c72d5ebd 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java @@ -56,8 +56,17 @@ public class GridColumnState implements Serializable { */ public int width = 100; + /** + * The connector for the renderer used to render the cells in this column. + */ public Connector rendererConnector; + /** + * The connector for the field used to edit cells in this column when the + * editor row is active. + */ + public Connector editorConnector; + /** * Are sorting indicators shown for a column. Default is false. */ 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 index 5a4568259d..5c19e29f17 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java @@ -15,16 +15,22 @@ */ 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.GridBasicClientFeaturesTest; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures; public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { @@ -71,4 +77,19 @@ public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { new Actions(getDriver()).sendKeys(Keys.ENTER).perform(); assertNull(getEditorRow()); } + + @Test + public void testWidgetBinding() throws Exception { + selectMenuPath("Component", "State", "Editor row", "Edit row 100"); + WebElement editorRow = getEditorRow(); + + List widgets = editorRow.findElements(By + .className("gwt-TextBox")); + + assertEquals(GridBasicFeatures.COLUMNS, widgets.size()); + + for (int i = 0; i < GridBasicFeatures.COLUMNS; ++i) { + assertEquals("Column " + i, widgets.get(i).getAttribute("value")); + } + } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index 9cf56439d8..8055508f71 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -27,8 +27,11 @@ 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.google.gwt.user.client.ui.Widget; 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; @@ -152,6 +155,14 @@ public class GridBasicClientFeaturesWidget extends grid.getElement().setId("testComponent"); grid.setDataSource(ds); grid.setSelectionMode(SelectionMode.NONE); + grid.getEditorRow().setHandler(new EditorRowHandler>() { + @Override + public Widget getWidget(GridColumn> column) { + TextBox tb = new TextBox(); + tb.setText("Column " + grid.getColumns().indexOf(column)); + return tb; + } + }); sorter = new ListSorter>(grid); -- cgit v1.2.3 From 49c9043762ca653b70ea4ea335862b5debdc3566 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Thu, 4 Sep 2014 16:33:41 +0300 Subject: Escalator tests for columns and rows (#13334) Change-Id: I258135dce0d78baf8d8483e6b24a2510161cee12 --- .../EscalatorBasicClientFeaturesTest.java | 20 ++ .../grid/basicfeatures/EscalatorRowColumnTest.java | 203 +++++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorRowColumnTest.java (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java index 745802a04f..4593e40155 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertTrue; 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; @@ -38,6 +39,12 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest 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)"; + @Override protected Class getUIClass() { return EscalatorBasicClientFeatures.class; @@ -125,4 +132,17 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest assertTrue("log did not contain: " + substring, log.getText().contains(substring)); } + + protected void scrollVerticallyTo(int px) { + executeScript("arguments[0].scrollTop = " + px, getVeticalScrollbar()); + } + + private WebElement getVeticalScrollbar() { + return getEscalator().findElement( + By.className("v-escalator-scroller-vertical")); + } + + protected Object executeScript(String script, Object... args) { + return ((JavascriptExecutor) getDriver()).executeScript(script, args); + } } 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)); + } +} -- cgit v1.2.3 From e3fe530dcefbdb7fa5ef7492302d3c1a58443501 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Wed, 10 Sep 2014 16:14:27 +0300 Subject: Tests Escalator's column spans (#13334) Change-Id: I3378f6b9bed4ee917c2244904ad07b5d38711ca2 --- .../EscalatorBasicClientFeaturesTest.java | 5 ++ .../grid/basicfeatures/EscalatorColspanTest.java | 91 ++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorColspanTest.java (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java index 4593e40155..c7fb66fa0d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java @@ -45,6 +45,11 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest 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 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; 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); + } +} -- cgit v1.2.3 From 8515bc3bb16ea0630880f8120d7c721584ed7524 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Thu, 11 Sep 2014 12:11:29 +0300 Subject: Bundles the logging label into a widget (#13334) Change-Id: I1c041c34dc4b08351122d0afc6de6fe2afadd48c --- .../grid/EscalatorBasicClientFeaturesWidget.java | 57 ++++++++++++++++-- .../widgetset/client/grid/EscalatorProxy.java | 67 ++++++---------------- 2 files changed, 69 insertions(+), 55 deletions(-) (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java index 068902ef0f..1af5940e64 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java @@ -3,7 +3,9 @@ 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.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; @@ -14,6 +16,50 @@ import com.vaadin.client.ui.grid.RowContainer; public class EscalatorBasicClientFeaturesWidget extends PureGWTTestApplication { + public static class LogWidget extends Composite { + + private static final int MAX_LOG = 9; + + private final HTML html = new HTML(); + private final List logs = new ArrayList(); + 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 = "
"; + for (String log : logs) { + logString += log + "
"; + } + + html.setHTML("Columns: " + columns + "
" + // + "Header rows: " + headers + "
" + // + "Body rows: " + bodys + "
" + // + "Footer rows: " + footers + "
" + // + logString); + } + + public void log(String string) { + logs.add((Duration.currentTimeMillis() % 10000) + ": " + string); + } + } + 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"; @@ -163,22 +209,23 @@ public class EscalatorBasicClientFeaturesWidget extends } } - private final Escalator escalator; + protected final Escalator escalator; private final Data data = new Data(); - private final HTML debugLabel = new HTML(); private enum Colspan { NONE, NORMAL, CRAZY; } private Colspan colspan = Colspan.NONE; + private final LogWidget logWidget = new LogWidget(); public EscalatorBasicClientFeaturesWidget() { super(new EscalatorProxy()); escalator = getTestedWidget(); - ((EscalatorProxy) escalator).setDebugLabel(debugLabel); - addNorth(debugLabel, 200); - debugLabel.getElement().setId("log"); + logWidget.setEscalator(escalator); + + ((EscalatorProxy) escalator).setLogWidget(logWidget); + addNorth(logWidget, 200); final RowContainer header = escalator.getHeader(); header.setEscalatorUpdater(data.createHeaderUpdater()); diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java index 5655684b82..ac1de01f1e 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java @@ -15,18 +15,14 @@ */ 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.dom.client.Element; import com.google.gwt.dom.client.TableRowElement; -import com.google.gwt.user.client.ui.HTML; 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 { @@ -40,16 +36,16 @@ public class EscalatorProxy extends Escalator { public void removeColumns(int index, int numberOfColumns) throws IndexOutOfBoundsException, IllegalArgumentException { columnConfiguration.removeColumns(index, numberOfColumns); - log("removeColumns " + index + ", " + numberOfColumns); - updateDebugLabel(); + logWidget.log("removeColumns " + index + ", " + numberOfColumns); + logWidget.updateDebugLabel(); } @Override public void insertColumns(int index, int numberOfColumns) throws IndexOutOfBoundsException, IllegalArgumentException { columnConfiguration.insertColumns(index, numberOfColumns); - log("insertColumns " + index + ", " + numberOfColumns); - updateDebugLabel(); + logWidget.log("insertColumns " + index + ", " + numberOfColumns); + logWidget.updateDebugLabel(); } @Override @@ -108,26 +104,26 @@ public class EscalatorProxy extends Escalator { public void removeRows(int index, int numberOfRows) throws IndexOutOfBoundsException, IllegalArgumentException { rowContainer.removeRows(index, numberOfRows); - log(rowContainer.getClass().getSimpleName() + " removeRows " - + index + ", " + numberOfRows); - updateDebugLabel(); + 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); - log(rowContainer.getClass().getSimpleName() + " insertRows " - + index + ", " + numberOfRows); - updateDebugLabel(); + 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); - log(rowContainer.getClass().getSimpleName() + " refreshRows " - + index + ", " + numberOfRows); + logWidget.log(rowContainer.getClass().getSimpleName() + + " refreshRows " + index + ", " + numberOfRows); } @Override @@ -163,14 +159,11 @@ public class EscalatorProxy extends Escalator { } - private static final int MAX_LOG = 9; - private RowContainer headerProxy = null; private RowContainer bodyProxy = null; private RowContainer footerProxy = null; private ColumnConfiguration columnProxy = null; - private HTML debugLabel; - private List logs = new ArrayList(); + private LogWidget logWidget; @Override public RowContainer getHeader() { @@ -205,35 +198,9 @@ public class EscalatorProxy extends Escalator { return columnProxy; } - public void setDebugLabel(HTML debugLabel) { - this.debugLabel = debugLabel; - updateDebugLabel(); - } - - public void updateDebugLabel() { - int headers = super.getHeader().getRowCount(); - int bodys = super.getBody().getRowCount(); - int footers = super.getFooter().getRowCount(); - int columns = super.getColumnConfiguration().getColumnCount(); - - while (logs.size() > MAX_LOG) { - logs.remove(0); - } - - String logString = "
"; - for (String log : logs) { - logString += log + "
"; - } - - debugLabel.setHTML( // - "Columns: " + columns + "
" + // - "Header rows: " + headers + "
" + // - "Body rows: " + bodys + "
" + // - "Footer rows: " + footers + "
" + // - logString); + public void setLogWidget(LogWidget logWidget) { + this.logWidget = logWidget; + logWidget.updateDebugLabel(); } - public void log(String string) { - logs.add((Duration.currentTimeMillis() % 10000) + ": " + string); - } } -- cgit v1.2.3 From 1c86bb28c71fe2ddcfddb210a9288cc78f13d172 Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Thu, 11 Sep 2014 14:59:22 +0300 Subject: Testing Escalator (post|pre)(Attach|Detach) functionality (#13334) Change-Id: If7a61560a96c5720b54bf3b5dcc83aef3ff7e357 --- .../EscalatorBasicClientFeaturesTest.java | 32 ++++- .../grid/basicfeatures/EscalatorUpdaterUi.java | 35 +++++ .../grid/basicfeatures/EscalatorUpdaterUiTest.java | 148 +++++++++++++++++++++ .../grid/EscalatorBasicClientFeaturesWidget.java | 56 +++++++- .../client/grid/EscalatorUpdaterTestConnector.java | 30 +++++ 5 files changed, 298 insertions(+), 3 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorUpdaterUi.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorUpdaterUiTest.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorUpdaterTestConnector.java (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java index c7fb66fa0d..5a282a15b6 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java @@ -15,7 +15,9 @@ */ 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; @@ -34,6 +36,8 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest 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"; @@ -133,9 +137,33 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest } 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")); - assertTrue("log did not contain: " + substring, - log.getText().contains(substring)); + 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) { 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/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java index 1af5940e64..54c870b8f7 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java @@ -5,6 +5,7 @@ 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; @@ -60,6 +61,59 @@ public class EscalatorBasicClientFeaturesWidget extends } } + public static class UpdaterLifetimeWidget extends + EscalatorBasicClientFeaturesWidget { + + private final EscalatorUpdater debugUpdater = new EscalatorUpdater() { + @Override + public void preAttach(Row row, Iterable cellsToAttach) { + log("preAttach", cellsToAttach); + } + + @Override + public void postAttach(Row row, + Iterable attachedCells) { + log("postAttach", attachedCells); + } + + @Override + public void update(Row row, Iterable cellsToUpdate) { + log("update", cellsToUpdate); + } + + @Override + public void preDetach(Row row, Iterable cellsToDetach) { + log("preDetach", cellsToDetach); + } + + @Override + public void postDetach(Row row, + Iterable detachedCells) { + log("postDetach", detachedCells); + } + + private void log(String methodName, Iterable 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"; @@ -217,7 +271,7 @@ public class EscalatorBasicClientFeaturesWidget extends } private Colspan colspan = Colspan.NONE; - private final LogWidget logWidget = new LogWidget(); + protected final LogWidget logWidget = new LogWidget(); public EscalatorBasicClientFeaturesWidget() { super(new EscalatorProxy()); 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(); + } +} -- cgit v1.2.3 From 8dfbccb322aea14863ab8b54b5bc268296b86fb5 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 10 Sep 2014 15:04:54 +0300 Subject: Implement data binding and edit cancel mechanism for editor row (#13334) This patch contains only the generic parts and a test EditorRowHandler. The Vaadin-specific implementation will be submitted as a separate change. Change-Id: I719a474fd72d7801a3b6c9cc567af1655b2f8565 --- .../src/com/vaadin/client/ui/grid/EditorRow.java | 20 +++-- .../vaadin/client/ui/grid/EditorRowHandler.java | 90 +++++++++++++++++++++- .../com/vaadin/client/ui/grid/GridConnector.java | 12 +++ .../client/GridEditorRowClientTest.java | 18 ++++- .../client/grid/GridBasicClientFeaturesWidget.java | 60 ++++++++++++--- 5 files changed, 179 insertions(+), 21 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/EditorRow.java b/client/src/com/vaadin/client/ui/grid/EditorRow.java index 9399898473..0c26dab851 100644 --- a/client/src/com/vaadin/client/ui/grid/EditorRow.java +++ b/client/src/com/vaadin/client/ui/grid/EditorRow.java @@ -27,6 +27,8 @@ import com.google.gwt.dom.client.TableRowElement; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.ui.grid.EditorRowHandler.EditorRowRequest; +import com.vaadin.client.ui.grid.EditorRowHandler.EditorRowRequest.RequestCallback; import com.vaadin.client.ui.grid.Escalator.AbstractRowContainer; import com.vaadin.client.ui.grid.ScrollbarBundle.Direction; import com.vaadin.shared.ui.grid.ScrollDestination; @@ -88,10 +90,7 @@ public class EditorRow { state = State.ACTIVATING; - boolean rowVisible = grid.getEscalator().getVisibleRowRange() - .contains(rowIndex); - - if (rowVisible) { + if (grid.getEscalator().getVisibleRowRange().contains(rowIndex)) { show(); } else { grid.scrollToRow(rowIndex, ScrollDestination.MIDDLE); @@ -115,6 +114,7 @@ public class EditorRow { } hideOverlay(); grid.getEscalator().setScrollLocked(Direction.VERTICAL, false); + handler.cancel(new EditorRowRequest(rowIndex, null)); state = State.INACTIVE; } @@ -174,9 +174,17 @@ public class EditorRow { protected void show() { if (state == State.ACTIVATING) { - state = State.ACTIVE; + handler.bind(new EditorRowRequest(rowIndex, new RequestCallback() { + @Override + public void onResponse(EditorRowRequest request) { + if (state == State.ACTIVATING) { + state = State.ACTIVE; + showOverlay(grid.getEscalator().getBody() + .getRowElement(request.getRowIndex())); + } + } + })); grid.getEscalator().setScrollLocked(Direction.VERTICAL, true); - showOverlay(grid.getEscalator().getBody().getRowElement(rowIndex)); } } diff --git a/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java b/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java index 43c43c67f6..ba3d0b9cd2 100644 --- a/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java +++ b/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java @@ -18,7 +18,12 @@ package com.vaadin.client.ui.grid; import com.google.gwt.user.client.ui.Widget; /** - * An interface for binding widgets and data to the editor row. + * An interface for binding widgets and data to the editor row. Used by the + * editor row to support different row types, data sources and custom data + * binding mechanisms. + * + * @param + * the row data type * * @since * @author Vaadin Ltd @@ -26,7 +31,88 @@ import com.google.gwt.user.client.ui.Widget; public interface EditorRowHandler { /** - * Returns the widget instance that is used to edit the values in the given + * A request class for handling asynchronous data binding. The request is + * callback-based to facilitate usage with remote or otherwise asynchronous + * data sources. + */ + public static class EditorRowRequest { + + /** + * A callback interface used to notify the caller about completed + * requests. + */ + public interface RequestCallback { + public void onResponse(EditorRowRequest request); + } + + private int rowIndex; + private RequestCallback callback; + + /** + * Creates a new editor row request. + * + * @param rowIndex + * the index of the edited row + * @param callback + * the callback invoked when the request is ready, or null if + * no need to call back + */ + public EditorRowRequest(int rowIndex, RequestCallback callback) { + this.rowIndex = rowIndex; + this.callback = callback; + } + + /** + * Returns the index of the row being requested. + * + * @return the row index + */ + public int getRowIndex() { + return rowIndex; + } + + /** + * Invokes the stored callback if it is not null. + */ + public void invokeCallback() { + if (callback != null) { + callback.onResponse(this); + } + } + } + + /** + * Binds row data to the editor row widgets. Called by the editor row when + * it is opened for editing. + *

+ * An implementation must call {@link EditorRowRequest#invokeCallback() + * request.invokeCallback()} when the binding is complete (possibly + * asynchronously). + * + * @param request + * the data binding request + * + * @see EditorRow#editRow(int) + */ + public void bind(EditorRowRequest request); + + /** + * Cancels a currently active edit if any. Called by the editor row when + * editing is cancelled. + *

+ * An implementation must call {@link EditorRowRequest#invokeCallback() + * request.invokeCallback()} when the cancel is done (possibly + * asynchronously). + * + * @param request + * the cancel request + * + * @see EditorRow#cancel() + */ + public void cancel(EditorRowRequest request); + + /** + * Returns a widget instance that is used to edit the values in the given * column. A null return value means the column is not editable. * * @param column diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 8ff467cfd5..8153a68f9e 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -150,6 +150,18 @@ public class GridConnector extends AbstractHasComponentsConnector { .getEditorConnector(); return c != null ? c.getWidget() : null; } + + @Override + public void bind(EditorRowRequest request) { + // TODO no-op until Vaadin comms implemented + request.invokeCallback(); + } + + @Override + public void cancel(EditorRowRequest request) { + // TODO no-op until Vaadin comms implemented + request.invokeCallback(); + } } /** 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 index 5c19e29f17..cf3b74a0c2 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java @@ -41,9 +41,14 @@ public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { } @Test - public void testProgrammaticOpening() { + 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 @@ -69,6 +74,8 @@ public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { 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"); @@ -88,8 +95,11 @@ public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { assertEquals(GridBasicFeatures.COLUMNS, widgets.size()); - for (int i = 0; i < GridBasicFeatures.COLUMNS; ++i) { - assertEquals("Column " + i, widgets.get(i).getAttribute("value")); - } + 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("100", widgets.get(9).getAttribute("value")); } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index 8055508f71..fcf1723db0 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -17,7 +17,9 @@ 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; @@ -28,7 +30,6 @@ 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.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.VLabel; import com.vaadin.client.ui.grid.Cell; import com.vaadin.client.ui.grid.EditorRowHandler; @@ -77,6 +78,46 @@ public class GridBasicClientFeaturesWidget extends TEXT_RENDERER, HTML_RENDERER, NUMBER_RENDERER, DATE_RENDERER; } + private class TestEditorRowHandler implements EditorRowHandler> { + + private Map, TextBox> widgets = new HashMap, TextBox>(); + + private Label log = new Label(); + + { + log.addStyleName("editor-row-log"); + addSouth(log, 20); + } + + @Override + public void bind(EditorRowRequest request) { + List rowData = ds.getRow(request.getRowIndex()); + + for (int i = 0; i < grid.getColumnCount(); i++) { + GridColumn> col = grid.getColumn(i); + getWidget(col).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 TextBox getWidget(GridColumn> column) { + TextBox w = widgets.get(column); + if (w == null) { + w = new TextBox(); + widgets.put(column, w); + } + return w; + } + } + private static final int MANUALLY_FORMATTED_COLUMNS = 5; public static final int COLUMNS = 12; public static final int ROWS = 1000; @@ -155,14 +196,7 @@ public class GridBasicClientFeaturesWidget extends grid.getElement().setId("testComponent"); grid.setDataSource(ds); grid.setSelectionMode(SelectionMode.NONE); - grid.getEditorRow().setHandler(new EditorRowHandler>() { - @Override - public Widget getWidget(GridColumn> column) { - TextBox tb = new TextBox(); - tb.setText("Column " + grid.getColumns().indexOf(column)); - return tb; - } - }); + grid.getEditorRow().setHandler(new TestEditorRowHandler()); sorter = new ListSorter>(grid); @@ -658,6 +692,14 @@ public class GridBasicClientFeaturesWidget extends grid.getEditorRow().editRow(100); } }, "Component", "Editor row"); + + addMenuCommand("Cancel edit", new ScheduledCommand() { + @Override + public void execute() { + grid.getEditorRow().cancel(); + } + }, "Component", "Editor row"); + } private void configureFooterRow(final FooterRow row) { -- cgit v1.2.3 From 861b57c196fa17f1488222125b9a89c38d6ad46d Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Wed, 10 Sep 2014 12:13:08 +0300 Subject: Tests Escalator's freezing columns. (#13334) Change-Id: Ifd85cfba770e31a91e05b854fde67c991f443c4d --- .../EscalatorBasicClientFeaturesTest.java | 13 +++ .../basicfeatures/EscalatorColumnFreezingTest.java | 112 +++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorColumnFreezingTest.java (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java index 5a282a15b6..eff964bd4f 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java @@ -50,6 +50,9 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest 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"; @@ -175,6 +178,16 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest 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/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; + } + } +} -- cgit v1.2.3 From e8820f89e97b62b719351bf79a7740ed5e983c83 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 15 Sep 2014 11:22:32 +0300 Subject: Prevent dispatching GridKeyEvents when target is not grid (#13334) Change-Id: I2efd6d48502360d14d21456077d50b37fa8a4be6 --- client/src/com/vaadin/client/ui/grid/Grid.java | 24 ++++++++++++++-------- .../client/ui/grid/events/GridKeyDownEvent.java | 9 ++++---- .../client/ui/grid/events/GridKeyPressEvent.java | 9 ++++---- .../client/ui/grid/events/GridKeyUpEvent.java | 9 ++++---- .../client/GridClientKeyEventsTest.java | 19 +++++++++++++++++ 5 files changed, 47 insertions(+), 23 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index a667bfa8dd..5221284c3c 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -135,7 +135,6 @@ public class Grid extends Composite implements private Grid grid; protected Cell activeCell; - protected GridSection activeSection; private final Type associatedType = new Type( getBrowserEventType(), this); @@ -165,16 +164,25 @@ public class Grid extends Composite implements @Override protected void dispatch(HANDLER handler) { - activeCell = grid.activeCellHandler.getActiveCell(); - activeSection = GridSection.FOOTER; - final RowContainer container = grid.activeCellHandler.container; - if (container == grid.escalator.getHeader()) { - activeSection = GridSection.HEADER; - } else if (container == grid.escalator.getBody()) { - activeSection = GridSection.BODY; + EventTarget target = getNativeEvent().getEventTarget(); + if (Element.is(target) + && Util.findWidget(Element.as(target), null) == grid) { + + activeCell = grid.activeCellHandler.getActiveCell(); + GridSection section = GridSection.FOOTER; + final RowContainer container = grid.activeCellHandler.container; + if (container == grid.escalator.getHeader()) { + section = GridSection.HEADER; + } else if (container == grid.escalator.getBody()) { + section = GridSection.BODY; + } + + doDispatch(handler, section); } } + protected abstract void doDispatch(HANDLER handler, GridSection seciton); + @Override public Type getAssociatedType() { return associatedType; diff --git a/client/src/com/vaadin/client/ui/grid/events/GridKeyDownEvent.java b/client/src/com/vaadin/client/ui/grid/events/GridKeyDownEvent.java index 2fab683bb0..81ff0e0a19 100644 --- a/client/src/com/vaadin/client/ui/grid/events/GridKeyDownEvent.java +++ b/client/src/com/vaadin/client/ui/grid/events/GridKeyDownEvent.java @@ -33,11 +33,10 @@ public class GridKeyDownEvent extends AbstractGridKeyEvent { } @Override - protected void dispatch(GridKeyDownHandler handler) { - super.dispatch(handler); - if ((activeSection == GridSection.BODY && handler instanceof BodyKeyDownHandler) - || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyDownHandler) - || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyDownHandler)) { + protected void doDispatch(GridKeyDownHandler handler, GridSection section) { + if ((section == GridSection.BODY && handler instanceof BodyKeyDownHandler) + || (section == GridSection.HEADER && handler instanceof HeaderKeyDownHandler) + || (section == GridSection.FOOTER && handler instanceof FooterKeyDownHandler)) { handler.onKeyDown(this); } } diff --git a/client/src/com/vaadin/client/ui/grid/events/GridKeyPressEvent.java b/client/src/com/vaadin/client/ui/grid/events/GridKeyPressEvent.java index 112200b03a..9033344597 100644 --- a/client/src/com/vaadin/client/ui/grid/events/GridKeyPressEvent.java +++ b/client/src/com/vaadin/client/ui/grid/events/GridKeyPressEvent.java @@ -34,11 +34,10 @@ public class GridKeyPressEvent extends } @Override - protected void dispatch(GridKeyPressHandler handler) { - super.dispatch(handler); - if ((activeSection == GridSection.BODY && handler instanceof BodyKeyPressHandler) - || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyPressHandler) - || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyPressHandler)) { + protected void doDispatch(GridKeyPressHandler handler, GridSection section) { + if ((section == GridSection.BODY && handler instanceof BodyKeyPressHandler) + || (section == GridSection.HEADER && handler instanceof HeaderKeyPressHandler) + || (section == GridSection.FOOTER && handler instanceof FooterKeyPressHandler)) { handler.onKeyPress(this); } } diff --git a/client/src/com/vaadin/client/ui/grid/events/GridKeyUpEvent.java b/client/src/com/vaadin/client/ui/grid/events/GridKeyUpEvent.java index 9aa8ce7084..623f3d5ed8 100644 --- a/client/src/com/vaadin/client/ui/grid/events/GridKeyUpEvent.java +++ b/client/src/com/vaadin/client/ui/grid/events/GridKeyUpEvent.java @@ -33,11 +33,10 @@ public class GridKeyUpEvent extends AbstractGridKeyEvent { } @Override - protected void dispatch(GridKeyUpHandler handler) { - super.dispatch(handler); - if ((activeSection == GridSection.BODY && handler instanceof BodyKeyUpHandler) - || (activeSection == GridSection.HEADER && handler instanceof HeaderKeyUpHandler) - || (activeSection == GridSection.FOOTER && handler instanceof FooterKeyUpHandler)) { + protected void doDispatch(GridKeyUpHandler handler, GridSection section) { + if ((section == GridSection.BODY && handler instanceof BodyKeyUpHandler) + || (section == GridSection.HEADER && handler instanceof HeaderKeyUpHandler) + || (section == GridSection.FOOTER && handler instanceof FooterKeyUpHandler)) { handler.onKeyUp(this); } } 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 index fe81380296..47bd9f6cb7 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientKeyEventsTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientKeyEventsTest.java @@ -27,6 +27,7 @@ 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 { @@ -105,4 +106,22 @@ public class GridClientKeyEventsTest extends GridBasicClientFeaturesTest { } } + @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()); + + } + } + } -- cgit v1.2.3 From f19ed54992d4f3ae7354ba7843b0a0ade0b593bd Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 9 Sep 2014 14:39:09 +0300 Subject: Fix client-side StaticRow to use GridColumn instead of index (#13334) Change-Id: I82e86c41de400e232fdf153379b8c40167bce438 --- client/src/com/vaadin/client/ui/grid/Grid.java | 47 +++---- .../com/vaadin/client/ui/grid/GridConnector.java | 7 +- .../vaadin/client/ui/grid/GridStaticSection.java | 156 +++++++++++---------- .../client/grid/GridBasicClientFeaturesWidget.java | 48 ++++--- .../grid/GridClientColumnRendererConnector.java | 25 ++-- 5 files changed, 143 insertions(+), 140 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 5221284c3c..b0f97413ff 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -403,8 +403,7 @@ public class Grid extends Composite implements --newRow; break; case KeyCodes.KEY_RIGHT: - if (activeCellRange.getEnd() >= getVisibleColumnIndices() - .size()) { + if (activeCellRange.getEnd() >= getVisibleColumns().size()) { return; } ++newColumn; @@ -1163,13 +1162,11 @@ public class Grid extends Composite implements public void update(Row row, Iterable cellsToUpdate) { GridStaticSection.StaticRow staticRow = section.getRow(row .getRow()); - - final List columnIndices = getVisibleColumnIndices(); + final List> columns = getVisibleColumns(); for (FlyweightCell cell : cellsToUpdate) { - - int index = columnIndices.get(cell.getColumn()); - final StaticCell metadata = staticRow.getCell(index); + final StaticCell metadata = staticRow.getCell(columns.get(cell + .getColumn())); // Decorate default row with sorting indicators if (staticRow instanceof HeaderRow) { @@ -1256,11 +1253,11 @@ public class Grid extends Composite implements public void postAttach(Row row, Iterable attachedCells) { GridStaticSection.StaticRow gridRow = section.getRow(row .getRow()); - List columnIndices = getVisibleColumnIndices(); + List> columns = getVisibleColumns(); for (FlyweightCell cell : attachedCells) { - int index = columnIndices.get(cell.getColumn()); - StaticCell metadata = gridRow.getCell(index); + StaticCell metadata = gridRow.getCell(columns.get(cell + .getColumn())); /* * If the cell contains widgets that are not currently attach * then attach them now. @@ -1286,10 +1283,10 @@ public class Grid extends Composite implements if (section.getRowCount() > row.getRow()) { GridStaticSection.StaticRow gridRow = section.getRow(row .getRow()); - List columnIndices = getVisibleColumnIndices(); + List> columns = getVisibleColumns(); for (FlyweightCell cell : cellsToDetach) { - int index = columnIndices.get(cell.getColumn()); - StaticCell metadata = gridRow.getCell(index); + StaticCell metadata = gridRow.getCell(columns.get(cell + .getColumn())); if (GridStaticCellType.WIDGET.equals(metadata.getType()) && metadata.getWidget().isAttached()) { @@ -1529,8 +1526,8 @@ public class Grid extends Composite implements // Register column with grid columns.add(index, column); - header.addColumn(column, index); - footer.addColumn(column, index); + header.addColumn(column); + footer.addColumn(column); // Register this grid instance with the column ((AbstractGridColumn) column).setGrid(this); @@ -1631,8 +1628,8 @@ public class Grid extends Composite implements int visibleIndex = findVisibleColumnIndex(column); columns.remove(columnIndex); - header.removeColumn(columnIndex); - footer.removeColumn(columnIndex); + header.removeColumn(column); + footer.removeColumn(column); // de-register column with grid ((AbstractGridColumn) column).setGrid(null); @@ -1686,18 +1683,18 @@ public class Grid extends Composite implements } /** - * Returns a list of column indices that are currently visible. + * Returns a list of columns that are currently visible. * - * @return a list of indices + * @return a list of columns */ - private List getVisibleColumnIndices() { - List indices = new ArrayList(getColumnCount()); - for (int i = 0; i < getColumnCount(); i++) { - if (getColumn(i).isVisible()) { - indices.add(i); + protected List> getVisibleColumns() { + List> visible = new ArrayList>(); + for (GridColumn column : getColumns()) { + if (column.isVisible()) { + visible.add(column); } } - return indices; + return visible; } /** diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 8153a68f9e..d9e6463d32 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -40,8 +40,6 @@ import com.vaadin.client.data.RpcDataSourceConnector.RpcDataSource; import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.AbstractHasComponentsConnector; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; -import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; -import com.vaadin.client.ui.grid.GridStaticSection.StaticRow; import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; import com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel; import com.vaadin.client.ui.grid.selection.SelectionChangeEvent; @@ -333,7 +331,7 @@ public class GridConnector extends AbstractHasComponentsConnector { } for (RowState rowState : state.rows) { - StaticRow row = section.appendRow(); + GridStaticSection.StaticRow row = section.appendRow(); int selectionOffset = 1; if (getWidget().getSelectionModel() instanceof SelectionModel.None) { @@ -345,7 +343,8 @@ public class GridConnector extends AbstractHasComponentsConnector { int i = 0 + selectionOffset; for (CellState cellState : rowState.cells) { - StaticCell cell = row.getCell(i++); + GridStaticSection.StaticCell cell = row.getCell(getWidget() + .getColumn(i++)); switch (cellState.type) { case TEXT: cell.setText(cellState.text); diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index 8c9ada46d0..05b809e156 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -18,8 +18,10 @@ package com.vaadin.client.ui.grid; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import com.google.gwt.user.client.ui.Widget; import com.vaadin.shared.ui.grid.GridStaticCellType; @@ -185,80 +187,63 @@ abstract class GridStaticSection> */ abstract static class StaticRow { - private List cells = new ArrayList(); + private Map, CELLTYPE> cells = new HashMap, CELLTYPE>(); private GridStaticSection section; - private Collection> cellGroups = new HashSet>(); + private Collection>> cellGroups = new HashSet>>(); /** - * Returns the cell at the given position in this row. + * Returns the cell on given GridColumn. * - * @param index - * the position of the cell - * @return the cell at the index - * @throws IndexOutOfBoundsException - * if the index is out of bounds + * @param column + * the column in grid + * @return the cell on given column, null if not found */ - public CELLTYPE getCell(int index) { - return cells.get(index); + public CELLTYPE getCell(GridColumn column) { + return cells.get(column); } /** - * Merges cells in a row + * Merges columns cells in a row * - * @param cells - * The cells to be merged - * @return The first cell of the merged cells + * @param columns + * the columns which header should be merged + * @return the remaining visible cell after the merge, or the cell on + * first column if all are hidden */ - protected CELLTYPE join(List cells) { - assert cells.size() > 1 : "You cannot merge less than 2 cells together"; - - // Ensure no cell is already grouped - for (CELLTYPE cell : cells) { - if (getCellGroupForCell(cell) != null) { - throw new IllegalStateException("Cell " + cell.getText() - + " is already grouped."); - } + public CELLTYPE join(GridColumn... columns) { + if (columns.length <= 1) { + throw new IllegalArgumentException( + "You can't merge less than 2 columns together."); } - // Ensure continuous range - int firstCellIndex = this.cells.indexOf(cells.get(0)); - for (int i = 0; i < cells.size(); i++) { - if (this.cells.get(firstCellIndex + i) != cells.get(i)) { + final List columnList = section.grid.getColumns(); + int firstIndex = columnList.indexOf(columns[0]); + int i = 0; + for (GridColumn column : columns) { + if (!cells.containsKey(column)) { + throw new IllegalArgumentException( + "Given column does not exists on row " + column); + } else if (getCellGroupForColumn(column) != null) { + throw new IllegalStateException( + "Column is already in a group."); + } else if (!column.equals(columnList.get(firstIndex + (i++)))) { throw new IllegalStateException( - "Cell range must be a continous range"); + "Columns are in invalid order or not in a continuous range"); } } - // Create a new group - cellGroups.add(new ArrayList(cells)); + cellGroups.add(Arrays.asList(columns)); - // Calculates colspans, triggers refresh on section implicitly calculateColspans(); - // Returns first cell of group - return cells.get(0); - } - - /** - * Merges columns cells in a row - * - * @param columns - * The columns which header should be merged - * @return The remaining visible cell after the merge - */ - public CELLTYPE join(GridColumn... columns) { - assert columns.length > 1 : "You cannot merge less than 2 columns together"; - - // Convert columns to cells - List cells = new ArrayList(); - for (GridColumn c : columns) { - int index = getSection().getGrid().getColumns().indexOf(c); - cells.add(this.cells.get(index)); + for (i = 0; i < columns.length; ++i) { + if (columns[i].isVisible()) { + return getCell(columns[i]); + } } - - return join(cells); + return getCell(columns[0]); } /** @@ -266,15 +251,41 @@ abstract class GridStaticSection> * * @param cells * The cells to merge. Must be from the same row. - * @return The remaining visible cell after the merge + * @return The remaining visible cell after the merge, or the first cell + * if all columns are hidden */ public CELLTYPE join(CELLTYPE... cells) { - return join(Arrays.asList(cells)); + if (cells.length <= 1) { + throw new IllegalArgumentException( + "You can't merge less than 2 cells together."); + } + + GridColumn[] columns = new GridColumn[cells.length]; + + int j = 0; + for (GridColumn column : this.cells.keySet()) { + CELLTYPE cell = this.cells.get(column); + if (!this.cells.containsValue(cells[j])) { + throw new IllegalArgumentException( + "Given cell does not exists on row"); + } else if (cell.equals(cells[j])) { + columns[j++] = column; + if (j == cells.length) { + break; + } + } else if (j > 0) { + throw new IllegalStateException( + "Cells are in invalid order or not in a continuous range."); + } + } + + return join(columns); } - private List getCellGroupForCell(CELLTYPE cell) { - for (List group : cellGroups) { - if (group.contains(cell)) { + private List> getCellGroupForColumn( + GridColumn column) { + for (List> group : cellGroups) { + if (group.contains(column)) { return group; } } @@ -284,12 +295,12 @@ abstract class GridStaticSection> void calculateColspans() { // Reset all cells - for (CELLTYPE cell : cells) { + for (CELLTYPE cell : this.cells.values()) { cell.setColspan(1); } // Set colspan for grouped cells - for (List group : cellGroups) { + for (List> group : cellGroups) { int firstVisibleColumnInGroup = -1; int lastVisibleColumnInGroup = -1; @@ -306,11 +317,7 @@ abstract class GridStaticSection> * visible cell and how many cells are hidden in between. */ for (int i = 0; i < group.size(); i++) { - CELLTYPE cell = group.get(i); - int cellIndex = this.cells.indexOf(cell); - boolean columnVisible = getSection().getGrid() - .getColumn(cellIndex).isVisible(); - if (columnVisible) { + if (group.get(i).isVisible()) { lastVisibleColumnInGroup = i; if (firstVisibleColumnInGroup == -1) { firstVisibleColumnInGroup = i; @@ -330,22 +337,23 @@ abstract class GridStaticSection> /* * Assign colspan to first cell in group. */ - CELLTYPE firstVisibleCell = group + GridColumn firstVisibleColumn = group .get(firstVisibleColumnInGroup); + CELLTYPE firstVisibleCell = getCell(firstVisibleColumn); firstVisibleCell.setColspan(lastVisibleColumnInGroup - firstVisibleColumnInGroup - hiddenInsideGroup + 1); } } - protected void addCell(int index) { + protected void addCell(GridColumn column) { CELLTYPE cell = createCell(); cell.setSection(getSection()); - cells.add(index, cell); + cells.put(column, cell); } - protected void removeCell(int index) { - cells.remove(index); + protected void removeCell(GridColumn column) { + cells.remove(column); } protected abstract CELLTYPE createCell(); @@ -415,7 +423,7 @@ abstract class GridStaticSection> ROWTYPE row = createRow(); row.setSection(this); for (int i = 0; i < getGrid().getColumnCount(); ++i) { - row.addCell(i); + row.addCell(grid.getColumn(i)); } rows.add(index, row); @@ -509,15 +517,15 @@ abstract class GridStaticSection> return isVisible() ? getRowCount() : 0; } - protected void addColumn(GridColumn column, int index) { + protected void addColumn(GridColumn column) { for (ROWTYPE row : rows) { - row.addCell(index); + row.addCell(column); } } - protected void removeColumn(int index) { + protected void removeColumn(GridColumn column) { for (ROWTYPE row : rows) { - row.removeCell(index); + row.removeCell(column); } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index fcf1723db0..0da8c1fc67 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -388,24 +388,22 @@ public class GridBasicClientFeaturesWidget extends for (int i = 0; i < COLUMNS; i++) { final int index = i; + final GridColumn> column = grid.getColumn(index); addMenuCommand("Visible", new ScheduledCommand() { @Override public void execute() { - grid.getColumn(index).setVisible( - !grid.getColumn(index).isVisible()); + column.setVisible(!column.isVisible()); } }, "Component", "Columns", "Column " + i); addMenuCommand("Sortable", new ScheduledCommand() { @Override public void execute() { - grid.getColumn(index).setSortable( - !grid.getColumn(index).isSortable()); + column.setSortable(!column.isSortable()); } }, "Component", "Columns", "Column " + i); addMenuCommand("Frozen", new ScheduledCommand() { @Override public void execute() { - GridColumn> column = grid.getColumn(index); if (column.equals(grid.getLastFrozenColumn())) { grid.setLastFrozenColumn(null); } else { @@ -417,19 +415,19 @@ public class GridBasicClientFeaturesWidget extends addMenuCommand("auto", new ScheduledCommand() { @Override public void execute() { - grid.getColumn(index).setWidth(-1); + column.setWidth(-1); } }, "Component", "Columns", "Column " + i, "Width"); addMenuCommand("50px", new ScheduledCommand() { @Override public void execute() { - grid.getColumn(index).setWidth(50); + column.setWidth(50); } }, "Component", "Columns", "Column " + i, "Width"); addMenuCommand("200px", new ScheduledCommand() { @Override public void execute() { - grid.getColumn(index).setWidth(200); + column.setWidth(200); } }, "Component", "Columns", "Column " + i, "Width"); @@ -437,14 +435,14 @@ public class GridBasicClientFeaturesWidget extends addMenuCommand("Text Header", new ScheduledCommand() { @Override public void execute() { - grid.getHeader().getRow(0).getCell(index) + 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(index) + grid.getHeader().getRow(0).getCell(column) .setHtml("HTML Header"); } }, "Component", "Columns", "Column " + i, "Header Type"); @@ -459,7 +457,8 @@ public class GridBasicClientFeaturesWidget extends button.setText("Clicked"); } }); - grid.getHeader().getRow(0).getCell(index).setWidget(button); + grid.getHeader().getRow(0).getCell(column) + .setWidget(button); } }, "Component", "Columns", "Column " + i, "Header Type"); @@ -467,14 +466,14 @@ public class GridBasicClientFeaturesWidget extends addMenuCommand("Text Footer", new ScheduledCommand() { @Override public void execute() { - grid.getFooter().getRow(0).getCell(index) + 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(index) + grid.getFooter().getRow(0).getCell(column) .setHtml("HTML Footer"); } }, "Component", "Columns", "Column " + i, "Footer Type"); @@ -489,7 +488,8 @@ public class GridBasicClientFeaturesWidget extends button.setText("Clicked"); } }); - grid.getFooter().getRow(0).getCell(index).setWidget(button); + grid.getFooter().getRow(0).getCell(column) + .setWidget(button); } }, "Component", "Columns", "Column " + i, "Footer Type"); } @@ -504,11 +504,12 @@ public class GridBasicClientFeaturesWidget extends // Lets use some different cell types if (i % 3 == 0) { - row.getCell(i).setText(caption); + row.getCell(grid.getColumn(i)).setText(caption); } else if (i % 2 == 0) { - row.getCell(i).setHtml("" + caption + ""); + row.getCell(grid.getColumn(i)) + .setHtml("" + caption + ""); } else { - row.getCell(i).setWidget(new HTML(caption)); + row.getCell(grid.getColumn(i)).setWidget(new HTML(caption)); } } headerCounter++; @@ -520,11 +521,12 @@ public class GridBasicClientFeaturesWidget extends // Lets use some different cell types if (i % 3 == 0) { - row.getCell(i).setText(caption); + row.getCell(grid.getColumn(i)).setText(caption); } else if (i % 2 == 0) { - row.getCell(i).setHtml("" + caption + ""); + row.getCell(grid.getColumn(i)) + .setHtml("" + caption + ""); } else { - row.getCell(i).setWidget(new HTML(caption)); + row.getCell(grid.getColumn(i)).setWidget(new HTML(caption)); } } footerCounter++; @@ -597,7 +599,8 @@ public class GridBasicClientFeaturesWidget extends @Override public void execute() { - row.join(row.getCell(0), row.getCell(1)); + row.join(row.getCell(grid.getColumn(0)), + row.getCell(grid.getColumn(1))); } }, menuPath); @@ -712,7 +715,8 @@ public class GridBasicClientFeaturesWidget extends @Override public void execute() { - row.join(row.getCell(0), row.getCell(1)); + row.join(row.getCell(grid.getColumn(0)), + row.getCell(grid.getColumn(1))); } }, menuPath); diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java index c5571394bd..f4ca1d0344 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java @@ -140,12 +140,12 @@ public class GridClientColumnRendererConnector extends // Add a column to display the data in GridColumn c = createColumnWithRenderer(Renderers.TEXT_RENDERER); grid.addColumn(c); - grid.getHeader().getDefaultRow().getCell(0).setText("Column 1"); + 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(1).setText("Column 2"); + grid.getHeader().getDefaultRow().getCell(c).setText("Column 2"); // Add method for testing sort event firing grid.addSortHandler(new SortEventHandler() { @@ -156,10 +156,9 @@ public class GridClientColumnRendererConnector extends String text = "Client-side sort event received
" + "Columns: " + event.getOrder().size() + ", order: "; for (SortOrder order : event.getOrder()) { - int colIdx = getWidget().getColumns().indexOf( - order.getColumn()); String columnHeader = getWidget().getHeader() - .getDefaultRow().getCell(colIdx).getText(); + .getDefaultRow().getCell(order.getColumn()) + .getText(); text += columnHeader + ": " + order.getDirection().toString(); } @@ -174,24 +173,20 @@ public class GridClientColumnRendererConnector extends @Override public void addColumn(Renderers renderer) { + GridColumn column; if (renderer == Renderers.NUMBER_RENDERER) { - GridColumn numberColumn = createNumberColumnWithRenderer(renderer); - getWidget().addColumn(numberColumn); - + column = createNumberColumnWithRenderer(renderer); } else if (renderer == Renderers.DATE_RENDERER) { - GridColumn dateColumn = createDateColumnWithRenderer(renderer); - getWidget().addColumn(dateColumn); - + column = createDateColumnWithRenderer(renderer); } else { - GridColumn column = createColumnWithRenderer(renderer); - getWidget().addColumn(column); + column = createColumnWithRenderer(renderer); } + getWidget().addColumn(column); - int idx = getWidget().getColumnCount() - 1; getWidget() .getHeader() .getDefaultRow() - .getCell(idx) + .getCell(column) .setText( "Column " + String.valueOf(getWidget() -- cgit v1.2.3 From bf5d4e375d6fed0dd01b77ac2de267f551326d5e Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Tue, 16 Sep 2014 15:42:52 +0300 Subject: Fixes an assumption bug with EditorRow (#13334) Change-Id: Ieabb3d10daf445b4cfc387b202ede4dde58a73f1 --- client/src/com/vaadin/client/ui/grid/EditorRow.java | 9 +++++++-- client/src/com/vaadin/client/ui/grid/Grid.java | 6 +++--- client/src/com/vaadin/client/ui/grid/GridConnector.java | 12 +++++++++--- .../basicfeatures/client/GridEditorRowClientTest.java | 17 +++++++++++++++++ .../client/grid/GridBasicClientFeaturesWidget.java | 12 ++++++++++-- 5 files changed, 46 insertions(+), 10 deletions(-) (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/EditorRow.java b/client/src/com/vaadin/client/ui/grid/EditorRow.java index 0c26dab851..68dd7aeea4 100644 --- a/client/src/com/vaadin/client/ui/grid/EditorRow.java +++ b/client/src/com/vaadin/client/ui/grid/EditorRow.java @@ -30,6 +30,7 @@ import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.grid.EditorRowHandler.EditorRowRequest; import com.vaadin.client.ui.grid.EditorRowHandler.EditorRowRequest.RequestCallback; import com.vaadin.client.ui.grid.Escalator.AbstractRowContainer; +import com.vaadin.client.ui.grid.Grid.SelectionColumn; import com.vaadin.client.ui.grid.ScrollbarBundle.Direction; import com.vaadin.shared.ui.grid.ScrollDestination; @@ -240,8 +241,12 @@ public class EditorRow { editorOverlay.appendChild(cell); - Widget editor = getHandler().getWidget( - grid.getColumnFromVisibleIndex(i)); + GridColumn column = grid.getColumnFromVisibleIndex(i); + if (column instanceof SelectionColumn) { + continue; + } + + Widget editor = getHandler().getWidget(column); if (editor != null) { editorWidgets.add(editor); cell.appendChild(editor.getElement()); diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 636fa78ea7..c0d4053150 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -566,14 +566,14 @@ public class Grid extends Composite implements } } - private class SelectionColumn extends GridColumn { + public final class SelectionColumn extends GridColumn { private boolean initDone = false; - public SelectionColumn(final Renderer selectColumnRenderer) { + SelectionColumn(final Renderer selectColumnRenderer) { super(selectColumnRenderer); } - public void initDone() { + void initDone() { initDone = true; } diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index d9e6463d32..8599c6df7d 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -144,9 +144,15 @@ public class GridConnector extends AbstractHasComponentsConnector { @Override public Widget getWidget(GridColumn column) { assert column != null; - AbstractFieldConnector c = ((CustomGridColumn) column) - .getEditorConnector(); - return c != null ? c.getWidget() : null; + + if (column instanceof CustomGridColumn) { + AbstractFieldConnector c = ((CustomGridColumn) column) + .getEditorConnector(); + return c != null ? c.getWidget() : null; + } else { + throw new IllegalStateException("Unexpected column type: " + + column.getClass().getName()); + } } @Override 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 index cf3b74a0c2..a37bf41072 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java @@ -16,8 +16,10 @@ 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; @@ -102,4 +104,19 @@ public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { assertEquals("100", widgets.get(7).getAttribute("value")); assertEquals("100", 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 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()); + } } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index 0da8c1fc67..5b69df1fb7 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -63,6 +63,7 @@ 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; /** @@ -93,8 +94,10 @@ public class GridBasicClientFeaturesWidget extends public void bind(EditorRowRequest request) { List rowData = ds.getRow(request.getRowIndex()); - for (int i = 0; i < grid.getColumnCount(); i++) { - GridColumn> col = grid.getColumn(i); + boolean hasSelectionColumn = !(grid.getSelectionModel() instanceof None); + for (int i = 0; i < rowData.size(); i++) { + int gridColumnIndex = hasSelectionColumn ? i + 1 : i; + GridColumn> col = grid.getColumn(gridColumnIndex); getWidget(col).setText(rowData.get(i).value.toString()); } @@ -109,6 +112,11 @@ public class GridBasicClientFeaturesWidget extends @Override public TextBox getWidget(GridColumn> column) { + if (grid.getColumns().indexOf(column) == 0 + && !(grid.getSelectionModel() instanceof None)) { + return null; + } + TextBox w = widgets.get(column); if (w == null) { w = new TextBox(); -- cgit v1.2.3 From fcb564daacec11992703e4821ae784c0d3b305dd Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 10 Sep 2014 15:21:09 +0300 Subject: Implement Vaadin-specific editor row bind/cancel handling (#13334) Change-Id: I9a6326a065b3ca159dd1b4237de1dbf8fa8e10ff --- .../com/vaadin/client/ui/grid/GridConnector.java | 83 +++++++++++-- .../com/vaadin/ui/components/grid/EditorRow.java | 133 +++++++++++++-------- server/src/com/vaadin/ui/components/grid/Grid.java | 37 +++++- .../server/component/grid/EditorRowTests.java | 23 +++- .../vaadin/shared/ui/grid/EditorRowClientRpc.java | 49 ++++++++ .../vaadin/shared/ui/grid/EditorRowServerRpc.java | 48 ++++++++ .../grid/basicfeatures/GridBasicFeatures.java | 29 +++++ .../basicfeatures/client/GridEditorRowTest.java | 64 ++++++++++ 8 files changed, 402 insertions(+), 64 deletions(-) create mode 100644 shared/src/com/vaadin/shared/ui/grid/EditorRowClientRpc.java create mode 100644 shared/src/com/vaadin/shared/ui/grid/EditorRowServerRpc.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 8599c6df7d..7c0a2da96d 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -52,6 +52,8 @@ 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.shared.ui.grid.EditorRowClientRpc; +import com.vaadin.shared.ui.grid.EditorRowServerRpc; import com.vaadin.shared.ui.grid.GridClientRpc; import com.vaadin.shared.ui.grid.GridColumnState; import com.vaadin.shared.ui.grid.GridServerRpc; @@ -138,9 +140,74 @@ public class GridConnector extends AbstractHasComponentsConnector { } } + /* + * An editor row handler using Vaadin RPC to manage the editor row state. + */ private class CustomEditorRowHandler implements EditorRowHandler { + private EditorRowServerRpc rpc = getRpcProxy(EditorRowServerRpc.class); + + private EditorRowRequest currentRequest = null; + private boolean serverInitiated = false; + + public CustomEditorRowHandler() { + registerRpc(EditorRowClientRpc.class, new EditorRowClientRpc() { + + @Override + public void bind(int rowIndex) { + serverInitiated = true; + GridConnector.this.getWidget().getEditorRow() + .editRow(rowIndex); + } + + @Override + public void cancel(int rowIndex) { + serverInitiated = true; + GridConnector.this.getWidget().getEditorRow().cancel(); + } + + @Override + public void confirmBind() { + endRequest(); + } + }); + } + + @Override + public void bind(EditorRowRequest request) { + int index = request.getRowIndex(); + + if (serverInitiated) { + /* + * EditorRow is calling us as a result of an RPC from the + * server, so no need to do another roundtrip. + */ + serverInitiated = false; + request.invokeCallback(); + } else { + /* + * The clientside wanted to open the editor row, so inform the + * server and proceed only when confirmation is received. + */ + startRequest(request); + rpc.bind(index); + } + } + + @Override + public void cancel(EditorRowRequest request) { + /* + * Tell the server to cancel unless it was the server that told us + * to cancel. Cancels don't need a confirmation. + */ + if (serverInitiated) { + serverInitiated = false; + } else { + rpc.cancel(request.getRowIndex()); + } + } + @Override public Widget getWidget(GridColumn column) { assert column != null; @@ -155,16 +222,16 @@ public class GridConnector extends AbstractHasComponentsConnector { } } - @Override - public void bind(EditorRowRequest request) { - // TODO no-op until Vaadin comms implemented - request.invokeCallback(); + private void startRequest(EditorRowRequest request) { + assert request != null; + assert currentRequest == null; + currentRequest = request; } - @Override - public void cancel(EditorRowRequest request) { - // TODO no-op until Vaadin comms implemented - request.invokeCallback(); + private void endRequest() { + assert currentRequest != null; + currentRequest.invokeCallback(); + currentRequest = null; } } diff --git a/server/src/com/vaadin/ui/components/grid/EditorRow.java b/server/src/com/vaadin/ui/components/grid/EditorRow.java index 18a5e8647b..2375627b89 100644 --- a/server/src/com/vaadin/ui/components/grid/EditorRow.java +++ b/server/src/com/vaadin/ui/components/grid/EditorRow.java @@ -16,9 +16,7 @@ package com.vaadin.ui.components.grid; import java.io.Serializable; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import com.vaadin.data.Container; @@ -78,7 +76,7 @@ public class EditorRow implements Serializable { */ public void setEnabled(boolean isEnabled) throws IllegalStateException { checkDetached(); - if (getEditedItemId() != null) { + if (isEditing()) { throw new IllegalStateException("Cannot disable the editor row " + "while an item (" + getEditedItemId() + ") is being edited."); @@ -107,7 +105,7 @@ public class EditorRow implements Serializable { public void setFieldGroup(FieldGroup fieldGroup) { checkDetached(); this.fieldGroup = fieldGroup; - if (editedItemId != null) { + if (isEditing()) { this.fieldGroup.setItemDataSource(getContainer().getItem( editedItemId)); } @@ -171,33 +169,21 @@ public class EditorRow implements Serializable { } /** - * Gets the field component that represents a property. + * Gets the field component that represents a property. If the property is + * not yet bound to a field, null is returned. *

- * If the property is not yet bound to a field, it will be bound during this - * call. Otherwise the previously bound field will be used. + * When {@link #editItem(Object) editItem} is called, fields are + * automatically created and bound to any unbound properties. * * @param propertyId * the property id of the property for which to find the field + * @return the bound field or null if not bound + * * @see #setPropertyUneditable(Object) */ public Field getField(Object propertyId) { checkDetached(); - - final Field field; - if (fieldGroup.getUnboundPropertyIds().contains(propertyId)) { - field = fieldGroup.buildAndBind(propertyId); - } else { - field = fieldGroup.getField(propertyId); - } - - if (field != null) { - boolean readonly = fieldGroup.isReadOnly() - || field.getPropertyDataSource().isReadOnly() - || !isPropertyEditable(propertyId); - field.setReadOnly(readonly); - } - - return field; + return fieldGroup.getField(propertyId); } /** @@ -218,6 +204,9 @@ public class EditorRow implements Serializable { public void setPropertyEditable(Object propertyId, boolean editable) { checkDetached(); checkPropertyExists(propertyId); + if (getField(propertyId) != null) { + getField(propertyId).setReadOnly(!editable); + } if (editable) { uneditableProperties.remove(propertyId); } else { @@ -272,6 +261,16 @@ public class EditorRow implements Serializable { */ void detach() { checkDetached(); + if (isEditing()) { + /* + * Simply force cancel the editing; throwing here would just make + * Grid.setContainerDataSource semantics more complicated. + */ + cancel(); + } + for (Field editor : getFields()) { + editor.setParent(null); + } grid = null; } @@ -290,6 +289,13 @@ public class EditorRow implements Serializable { IllegalArgumentException { checkDetached(); + internalEditItem(itemId); + + grid.getEditorRowRpc().bind( + grid.getContainerDatasource().indexOfId(itemId)); + } + + protected void internalEditItem(Object itemId) { if (!isEnabled()) { throw new IllegalStateException("This " + getClass().getSimpleName() + " is not enabled"); @@ -303,6 +309,52 @@ public class EditorRow implements Serializable { fieldGroup.setItemDataSource(item); editedItemId = itemId; + + for (Object propertyId : item.getItemPropertyIds()) { + + final Field editor; + if (fieldGroup.getUnboundPropertyIds().contains(propertyId)) { + editor = fieldGroup.buildAndBind(propertyId); + } else { + editor = fieldGroup.getField(propertyId); + } + + grid.getColumn(propertyId).getState().editorConnector = editor; + + if (editor != null) { + editor.setReadOnly(!isPropertyEditable(propertyId)); + + if (editor.getParent() != grid) { + assert editor.getParent() == null; + editor.setParent(grid); + } + } + } + } + + /** + * Cancels the currently active edit if any. + */ + public void cancel() { + checkDetached(); + if (isEditing()) { + grid.getEditorRowRpc().cancel( + grid.getContainerDatasource().indexOfId(editedItemId)); + internalCancel(); + } + } + + protected void internalCancel() { + editedItemId = null; + } + + /** + * Returns whether this editor row is currently editing an item. + * + * @return true iff this editor row is editing an item + */ + public boolean isEditing() { + return editedItemId != null; } /** @@ -317,42 +369,19 @@ public class EditorRow implements Serializable { } /** - * Gets a collection of all fields represented by this editor row. + * Gets a collection of all fields bound to this editor row. *

* All non-editable fields (either readonly or uneditable) are in read-only * mode. + *

+ * When {@link #editItem(Object) editItem} is called, fields are + * automatically created and bound to any unbound properties. * - * @return a collection of all the fields represented by this editor row + * @return a collection of all the fields bound to this editor row */ Collection> getFields() { checkDetached(); - /* - * Maybe this isn't the best idea, however. Maybe the components should - * always be transferred over the wire, to increase up-front load-time - * and decrease on-demand load-time. - */ - if (!isEnabled()) { - return Collections.emptySet(); - } - - for (Object propertyId : fieldGroup.getUnboundPropertyIds()) { - fieldGroup.buildAndBind(propertyId); - } - - /* - * We'll collect this ourselves instead of asking fieldGroup.getFields() - * because we might have marked something as uneditable even though it - * might not read-only. - */ - ArrayList> fields = new ArrayList>(); - for (Object propertyId : getContainer().getContainerPropertyIds()) { - Field field = getField(propertyId); - if (field != null) { - fields.add(field); - } - } - - return fields; + return fieldGroup.getFields(); } private Container getContainer() { diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 1a6f333e48..77773e7743 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -37,6 +37,8 @@ import com.vaadin.data.Container.Sortable; import com.vaadin.data.RpcDataProviderExtension; import com.vaadin.data.RpcDataProviderExtension.DataProviderKeyMapper; import com.vaadin.server.KeyMapper; +import com.vaadin.shared.ui.grid.EditorRowClientRpc; +import com.vaadin.shared.ui.grid.EditorRowServerRpc; import com.vaadin.shared.ui.grid.GridClientRpc; import com.vaadin.shared.ui.grid.GridColumnState; import com.vaadin.shared.ui.grid.GridServerRpc; @@ -49,7 +51,7 @@ import com.vaadin.shared.ui.grid.SortDirection; import com.vaadin.shared.ui.grid.SortEventOriginator; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Component; -import com.vaadin.ui.HasComponents; +import com.vaadin.ui.SelectiveRenderer; import com.vaadin.ui.components.grid.GridFooter.FooterCell; import com.vaadin.ui.components.grid.GridFooter.FooterRow; import com.vaadin.ui.components.grid.GridHeader.HeaderCell; @@ -131,7 +133,7 @@ import elemental.json.JsonArray; * @author Vaadin Ltd */ public class Grid extends AbstractComponent implements SelectionChangeNotifier, - HasComponents { + SelectiveRenderer { /** * Selection modes representing built-in {@link SelectionModel @@ -389,6 +391,21 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, setSortOrder(order, originator); } }); + + registerRpc(new EditorRowServerRpc() { + + @Override + public void bind(int rowIndex) { + getEditorRow().internalEditItem( + datasource.getIdByIndex(rowIndex)); + getEditorRowRpc().confirmBind(); + } + + @Override + public void cancel(int rowIndex) { + getEditorRow().internalCancel(); + } + }); } /** @@ -1316,6 +1333,18 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, return componentList.iterator(); } + @Override + public boolean isRendered(Component childComponent) { + if (getEditorRow().getFields().contains(childComponent)) { + // Only render editor row fields if the editor is open + return getEditorRow().isEditing(); + } else { + // TODO Header and footer components should also only be rendered if + // the header/footer is visible + return true; + } + } + /** * Gets the editor row configuration object. * @@ -1324,4 +1353,8 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, public EditorRow getEditorRow() { return editorRow; } + + EditorRowClientRpc getEditorRowRpc() { + return getRpcProxy(EditorRowClientRpc.class); + } } diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/EditorRowTests.java b/server/tests/src/com/vaadin/tests/server/component/grid/EditorRowTests.java index 36c541c99c..597db55337 100644 --- a/server/tests/src/com/vaadin/tests/server/component/grid/EditorRowTests.java +++ b/server/tests/src/com/vaadin/tests/server/component/grid/EditorRowTests.java @@ -22,11 +22,16 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import org.easymock.EasyMock; +import org.junit.After; import org.junit.Before; import org.junit.Test; import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; +import com.vaadin.server.MockVaadinSession; +import com.vaadin.server.VaadinService; +import com.vaadin.server.VaadinSession; import com.vaadin.ui.Field; import com.vaadin.ui.TextField; import com.vaadin.ui.components.grid.EditorRow; @@ -55,6 +60,19 @@ public class EditorRowTests { grid = new Grid(container); row = grid.getEditorRow(); + + // VaadinSession needed for ConverterFactory + VaadinService mockService = EasyMock + .createNiceMock(VaadinService.class); + VaadinSession session = new MockVaadinSession(mockService); + VaadinSession.setCurrent(session); + session.lock(); + } + + @After + public void tearDown() { + VaadinSession.getCurrent().unlock(); + VaadinSession.setCurrent(null); } @Test @@ -188,10 +206,11 @@ public class EditorRowTests { @Test public void customBinding() { - startEdit(); - TextField textField = new TextField(); row.bind(PROPERTY_NAME, textField); + + startEdit(); + assertSame(textField, row.getField(PROPERTY_NAME)); } diff --git a/shared/src/com/vaadin/shared/ui/grid/EditorRowClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/EditorRowClientRpc.java new file mode 100644 index 0000000000..1c99a5035d --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/EditorRowClientRpc.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.shared.ui.grid; + +import com.vaadin.shared.communication.ClientRpc; + +/** + * An RPC interface for the grid editor row server-to-client communications. + * + * @since + * @author Vaadin Ltd + */ +public interface EditorRowClientRpc extends ClientRpc { + + /** + * Tells the client to open the editor row and bind data to it. + * + * @param rowIndex + * the index of the edited row + */ + void bind(int rowIndex); + + /** + * Tells the client to cancel editing and hide the editor row. + * + * @param rowIndex + * the index of the edited row + */ + void cancel(int rowIndex); + + /** + * Confirms a pending {@link EditorRowServerRpc#bind(int) bind request} sent + * by the client. + */ + void confirmBind(); +} diff --git a/shared/src/com/vaadin/shared/ui/grid/EditorRowServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/EditorRowServerRpc.java new file mode 100644 index 0000000000..45705ca924 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/EditorRowServerRpc.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.shared.ui.grid; + +import com.vaadin.shared.communication.ServerRpc; + +/** + * An RPC interface for the grid editor row client-to-server communications. + * + * @since + * @author Vaadin Ltd + */ +public interface EditorRowServerRpc extends ServerRpc { + + /** + * Asks the server to open the editor row and bind data to it. When a bind + * request is sent, it must be acknowledged with a + * {@link EditorRowClientRpc#confirmBind() confirm call} before the client + * can open the editor. + * + * @param rowIndex + * the index of the edited row + */ + void bind(int rowIndex); + + /** + * Tells the server to cancel editing. When sending a cancel request, the + * client does not need to wait for confirmation by the server before hiding + * the editor row. + * + * @param rowIndex + * the index of the edited row + */ + void cancel(int rowIndex); +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 0802fcffe5..ae8a0d5eb8 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -109,6 +109,8 @@ public class GridBasicFeatures extends AbstractComponentTest { 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( @@ -190,6 +192,8 @@ public class GridBasicFeatures extends AbstractComponentTest { grid.setSelectionMode(SelectionMode.NONE); + grid.getEditorRow().setPropertyEditable(getColumnProperty(3), false); + createGridActions(); createColumnActions(); @@ -655,6 +659,31 @@ public class GridBasicFeatures extends AbstractComponentTest { c.getEditorRow().setEnabled(value); } }); + + createClickAction("Edit item 5", "Editor row", + new Command() { + @Override + public void execute(Grid c, String value, Object data) { + c.getEditorRow().editItem(5); + } + }, null); + + createClickAction("Edit item 100", "Editor row", + new Command() { + @Override + public void execute(Grid c, String value, Object data) { + c.getEditorRow().editItem(100); + } + }, null); + + createClickAction("Cancel edit", "Editor row", + new Command() { + @Override + public void execute(Grid c, String value, Object data) { + c.getEditorRow().cancel(); + } + }, null); + } @SuppressWarnings("boxing") 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 index f82702d432..7ca3894060 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowTest.java @@ -15,14 +15,21 @@ */ 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 { @@ -33,6 +40,48 @@ public class GridEditorRowTest extends GridBasicFeaturesTest { 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() { @@ -52,4 +101,19 @@ public class GridEditorRowTest extends GridBasicFeaturesTest { new Actions(getDriver()).sendKeys(Keys.ENTER).perform(); assertNull(getEditorRow()); } + + @Test + public void testComponentBinding() { + selectMenuPath("Component", "State", "Editor row", "Edit item 100"); + + List 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("100", widgets.get(9).getAttribute("value")); + } } -- cgit v1.2.3 From bb286a0c177551269a9d1eccc02978beeb71a4ee Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Fri, 12 Sep 2014 15:48:38 +0300 Subject: Implement commit/discard functionality for editor row (#13334) Includes commit and cancel UI. Vaadin-specific commit/discard implementation will be submitted as a separate patch. As of now, commits are assumed to always succeed. Change-Id: I2043eac2fe80012bee235648b01518f19057c215 --- WebContent/VAADIN/themes/base/grid/grid.scss | 7 ++ .../src/com/vaadin/client/ui/grid/EditorRow.java | 97 ++++++++++++++++++++-- .../vaadin/client/ui/grid/EditorRowHandler.java | 24 ++++++ .../com/vaadin/client/ui/grid/GridConnector.java | 12 +++ .../client/GridEditorRowClientTest.java | 34 +++++++- .../client/grid/GridBasicClientFeaturesWidget.java | 52 +++++++++++- 6 files changed, 217 insertions(+), 9 deletions(-) (limited to 'uitest/src') diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index de38b8c1ff..69b293e26e 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -39,12 +39,19 @@ .#{$primaryStyleName}-editor-row { position: absolute; + overflow-y: visible; background: #EEE; box-shadow: 0 0 5px; & > div { position: absolute; + box-sizing: border-box; border: 1px solid #CCC; } + + .v-editor-row-save, + .v-editor-row-cancel { + position: absolute; + } } } diff --git a/client/src/com/vaadin/client/ui/grid/EditorRow.java b/client/src/com/vaadin/client/ui/grid/EditorRow.java index ddef7c3dc7..a748af172f 100644 --- a/client/src/com/vaadin/client/ui/grid/EditorRow.java +++ b/client/src/com/vaadin/client/ui/grid/EditorRow.java @@ -24,9 +24,12 @@ import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.dom.client.TableRowElement; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.grid.EditorRowHandler.EditorRowRequest; import com.vaadin.client.ui.grid.EditorRowHandler.EditorRowRequest.RequestCallback; @@ -79,8 +82,9 @@ public class EditorRow { * the index of the row to be edited * * @throws IllegalStateException - * if this editor row is not enabled or if it is already in edit - * mode + * if this editor row is not enabled + * @throws IllegalStateException + * if this editor row is already in edit mode */ public void editRow(int rowIndex) { if (!enabled) { @@ -104,9 +108,12 @@ public class EditorRow { } /** - * Cancels the currently active edit and hides the editor. + * Cancels the currently active edit and hides the editor. Any changes that + * are not {@link #commit() committed} are lost. * * @throws IllegalStateException + * if this editor row is not enabled + * @throws IllegalStateException * if this editor row is not in edit mode */ public void cancel() { @@ -124,6 +131,56 @@ public class EditorRow { state = State.INACTIVE; } + /** + * Commits any unsaved changes to the data source. + * + * @throws IllegalStateException + * if this editor row is not enabled + * @throws IllegalStateException + * if this editor row is not in edit mode + */ + public void commit() { + if (!enabled) { + throw new IllegalStateException( + "Cannot commit: EditorRow is not enabled"); + } + if (state != State.ACTIVE) { + throw new IllegalStateException( + "Cannot commit: EditorRow is not in edit mode"); + } + + state = State.COMMITTING; + + handler.commit(new EditorRowRequest(rowIndex, new RequestCallback() { + @Override + public void onResponse(EditorRowRequest request) { + if (state == State.COMMITTING) { + state = State.ACTIVE; + } + } + })); + } + + /** + * Reloads row values from the data source, discarding any unsaved changes. + * + * @throws IllegalStateException + * if this editor row is not enabled + * @throws IllegalStateException + * if this editor row is not in edit mode + */ + public void discard() { + if (!enabled) { + throw new IllegalStateException( + "Cannot discard: EditorRow is not enabled"); + } + if (state != State.ACTIVE) { + throw new IllegalStateException( + "Cannot discard: EditorRow is not in edit mode"); + } + handler.discard(new EditorRowRequest(rowIndex, null)); + } + /** * Returns the handler responsible for binding data and editor widgets to * this editor row. @@ -263,10 +320,35 @@ public class EditorRow { Widget editor = getHandler().getWidget(column); if (editor != null) { editorWidgets.add(editor); - cell.appendChild(editor.getElement()); - Grid.setParent(editor, grid); + attachWidget(editor, cell); } } + + Button save = new Button(); + save.setText("Save"); + save.setStyleName("v-editor-row-save"); + save.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + // TODO should have a mechanism for handling failed commits + commit(); + cancel(); + } + }); + setBounds(save.getElement(), 0, tr.getOffsetHeight() + 5, 50, 25); + attachWidget(save, editorOverlay); + + Button cancel = new Button(); + cancel.setText("Cancel"); + cancel.setStyleName("v-editor-row-cancel"); + cancel.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + cancel(); + } + }); + setBounds(cancel.getElement(), 55, tr.getOffsetHeight() + 5, 50, 25); + attachWidget(cancel, editorOverlay); } protected void hideOverlay() { @@ -305,6 +387,11 @@ public class EditorRow { return cell; } + private void attachWidget(Widget w, Element parent) { + parent.appendChild(w.getElement()); + Grid.setParent(w, grid); + } + private static void setBounds(Element e, int left, int top, int width, int height) { Style style = e.getStyle(); diff --git a/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java b/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java index ba3d0b9cd2..d2d1e61efb 100644 --- a/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java +++ b/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java @@ -34,6 +34,8 @@ public interface EditorRowHandler { * A request class for handling asynchronous data binding. The request is * callback-based to facilitate usage with remote or otherwise asynchronous * data sources. + *

+ * TODO Should have a mechanism for signaling a failed request to the caller */ public static class EditorRowRequest { @@ -111,6 +113,28 @@ public interface EditorRowHandler { */ public void cancel(EditorRowRequest request); + /** + * Commits changes in the currently active edit to the data source. Called + * by the editor row when changes are saved. + * + * @param request + * the commit request + */ + public void commit(EditorRowRequest request); + + /** + * Discards any unsaved changes and reloads editor content from the data + * source. + *

+ * Implementation note: This method may simply call + * {@link #bind(EditorRowRequest) bind} if no other processing needs to be + * done. + * + * @param request + * the discard request + */ + public void discard(EditorRowRequest request); + /** * Returns a widget instance that is used to edit the values in the given * column. A null return value means the column is not editable. diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 7c0a2da96d..050f312d7e 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -233,6 +233,18 @@ public class GridConnector extends AbstractHasComponentsConnector { currentRequest.invokeCallback(); currentRequest = null; } + + @Override + public void commit(EditorRowRequest request) { + // TODO no-op until Vaadin comms implemented + request.invokeCallback(); + } + + @Override + public void discard(EditorRowRequest request) { + // TODO no-op until Vaadin comms implemented + request.invokeCallback(); + } } /** 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 index a37bf41072..4c64eac6e5 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java @@ -89,7 +89,7 @@ public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { @Test public void testWidgetBinding() throws Exception { - selectMenuPath("Component", "State", "Editor row", "Edit row 100"); + selectMenuPath("Component", "Editor row", "Edit row 100"); WebElement editorRow = getEditorRow(); List widgets = editorRow.findElements(By @@ -119,4 +119,36 @@ public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { 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 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 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/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index 5b69df1fb7..d5d276c7db 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -23,6 +23,7 @@ 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; @@ -96,9 +97,8 @@ public class GridBasicClientFeaturesWidget extends boolean hasSelectionColumn = !(grid.getSelectionModel() instanceof None); for (int i = 0; i < rowData.size(); i++) { - int gridColumnIndex = hasSelectionColumn ? i + 1 : i; - GridColumn> col = grid.getColumn(gridColumnIndex); - getWidget(col).setText(rowData.get(i).value.toString()); + int columnIndex = hasSelectionColumn ? i + 1 : i; + getWidget(columnIndex).setText(rowData.get(i).value.toString()); } request.invokeCallback(); @@ -110,6 +110,33 @@ public class GridBasicClientFeaturesWidget extends request.invokeCallback(); } + @Override + public void commit(EditorRowRequest request) { + log.setText("Row " + request.getRowIndex() + " edit committed"); + List 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> column) { if (grid.getColumns().indexOf(column) == 0 @@ -120,10 +147,15 @@ public class GridBasicClientFeaturesWidget extends 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; @@ -704,6 +736,20 @@ public class GridBasicClientFeaturesWidget extends } }, "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() { -- cgit v1.2.3