diff options
author | Ansku <Ansku@users.noreply.github.com> | 2017-08-22 14:59:49 +0300 |
---|---|---|
committer | Aleksi Hietanen <aleksi@vaadin.com> | 2017-08-22 14:59:49 +0300 |
commit | 3b2bea5236718fb13c9885141c0a4dddb323a868 (patch) | |
tree | c701551cf723e5ca4424574f96db627fb3457b14 | |
parent | 5ef925daa91b1253f170f244e2a992f4f92979e1 (diff) | |
download | vaadin-framework-3b2bea5236718fb13c9885141c0a4dddb323a868.tar.gz vaadin-framework-3b2bea5236718fb13c9885141c0a4dddb323a868.zip |
Resize should work within Grid details row (#9808)
Fixes #7341
8 files changed, 779 insertions, 9 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/DetailsManagerConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/DetailsManagerConnector.java index a1f9336c40..b8889591da 100644 --- a/client/src/main/java/com/vaadin/client/connectors/grid/DetailsManagerConnector.java +++ b/client/src/main/java/com/vaadin/client/connectors/grid/DetailsManagerConnector.java @@ -19,14 +19,18 @@ import java.util.HashMap; import java.util.Map; 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.user.client.ui.Widget; - import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorMap; import com.vaadin.client.LayoutManager; import com.vaadin.client.ServerConnector; +import com.vaadin.client.WidgetUtil; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.extensions.AbstractExtensionConnector; +import com.vaadin.client.ui.layout.ElementResizeEvent; +import com.vaadin.client.ui.layout.ElementResizeListener; import com.vaadin.client.widget.grid.HeightAwareDetailsGenerator; import com.vaadin.client.widgets.Grid; import com.vaadin.shared.Registration; @@ -53,6 +57,21 @@ public class DetailsManagerConnector extends AbstractExtensionConnector { /* Registration for data change handler. */ private Registration dataChangeRegistration; + private final Map<Element, ScheduledCommand> elementToResizeCommand = new HashMap<Element, Scheduler.ScheduledCommand>(); + private final ElementResizeListener detailsRowResizeListener = new ElementResizeListener() { + + @Override + public void onElementResize(ElementResizeEvent e) { + if (elementToResizeCommand.containsKey(e.getElement())) { + Scheduler.get().scheduleFinally( + elementToResizeCommand.get(e.getElement())); + } + } + }; + + /* calculated when the first details row is opened */ + private Double spacerCellBorderHeights = null; + /** * DataChangeHandler for updating the visibility of detail widgets. */ @@ -107,7 +126,35 @@ public class DetailsManagerConnector extends AbstractExtensionConnector { return null; } - return getConnector(id).getWidget(); + Widget widget = getConnector(id).getWidget(); + getLayoutManager().addElementResizeListener(widget.getElement(), + detailsRowResizeListener); + elementToResizeCommand.put(widget.getElement(), + createResizeCommand(rowIndex, widget.getElement())); + + return widget; + } + + private ScheduledCommand createResizeCommand(final int rowIndex, + final Element element) { + return new ScheduledCommand() { + + @Override + public void execute() { + // It should not be possible to get here without calculating + // the spacerCellBorderHeights or without having the details + // row open, nor for this command to be triggered while + // layout is running, but it's safer to check anyway. + if (spacerCellBorderHeights != null + && !getLayoutManager().isLayoutRunning() + && getDetailsComponentConnectorId( + rowIndex) != null) { + double height = getLayoutManager().getOuterHeightDouble( + element) + spacerCellBorderHeights; + getWidget().setDetailsHeight(rowIndex, height); + } + } + }; } @Override @@ -120,8 +167,16 @@ public class DetailsManagerConnector extends AbstractExtensionConnector { getLayoutManager().setNeedsMeasureRecursively(componentConnector); getLayoutManager().layoutNow(); - return getLayoutManager().getOuterHeightDouble( - componentConnector.getWidget().getElement()); + Element element = componentConnector.getWidget().getElement(); + if (spacerCellBorderHeights == null) { + // If theme is changed, new details generator is created from + // scratch, so this value doesn't need to be updated elsewhere. + spacerCellBorderHeights = WidgetUtil + .getBorderTopAndBottomThickness( + element.getParentElement()); + } + + return getLayoutManager().getOuterHeightDouble(element); } private ComponentConnector getConnector(String id) { @@ -143,7 +198,21 @@ public class DetailsManagerConnector extends AbstractExtensionConnector { return; } - // New Details component, hide old one + if (id == null) { + // Details have been hidden, listeners attached to the old + // component need to be removed + id = indexToDetailConnectorId.get(rowIndex); + } + + // New or removed Details component, hide old one + ComponentConnector connector = (ComponentConnector) ConnectorMap + .get(getConnection()).getConnector(id); + if (connector != null) { + Element element = connector.getWidget().getElement(); + elementToResizeCommand.remove(element); + getLayoutManager().removeElementResizeListener(element, + detailsRowResizeListener); + } getWidget().setDetailsVisible(rowIndex, false); indexToDetailConnectorId.remove(rowIndex); } diff --git a/client/src/main/java/com/vaadin/client/widgets/Grid.java b/client/src/main/java/com/vaadin/client/widgets/Grid.java index 267dbccc87..0de0c9ab7e 100755 --- a/client/src/main/java/com/vaadin/client/widgets/Grid.java +++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java @@ -9119,6 +9119,19 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, } /** + * Update details row height. + * + * @since + * @param rowIndex + * the index of the row for which to update details height + * @param height + * new height of the details row + */ + public void setDetailsHeight(int rowIndex, double height) { + escalator.getBody().setSpacer(rowIndex, height); + } + + /** * Requests that the column widths should be recalculated. * <p> * The actual recalculation is not necessarily done immediately so you diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java b/compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java index 87a4c90360..771f06881a 100644 --- a/compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java +++ b/compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java @@ -50,6 +50,8 @@ import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.AbstractHasComponentsConnector; import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; import com.vaadin.client.ui.SimpleManagedLayout; +import com.vaadin.client.ui.layout.ElementResizeEvent; +import com.vaadin.client.ui.layout.ElementResizeListener; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.ui.Connect; @@ -496,17 +498,67 @@ public class GridConnector extends AbstractHasComponentsConnector private final Map<String, ComponentConnector> idToDetailsMap = new HashMap<String, ComponentConnector>(); private final Map<String, Integer> idToRowIndex = new HashMap<String, Integer>(); + private final Map<Element, ScheduledCommand> elementToResizeCommand = new HashMap<Element, Scheduler.ScheduledCommand>(); + private final ElementResizeListener detailsRowResizeListener = new ElementResizeListener() { + + @Override + public void onElementResize(ElementResizeEvent e) { + if (elementToResizeCommand.containsKey(e.getElement())) { + Scheduler.get().scheduleFinally( + elementToResizeCommand.get(e.getElement())); + } + } + }; + + /* calculated when the first details row is opened */ + private Double spacerCellBorderHeights = null; @Override public Widget getDetails(int rowIndex) { String id = getId(rowIndex); - if (id == null) { + if (id == null || !hasDetailsOpen(rowIndex)) { return null; } ComponentConnector componentConnector = idToDetailsMap.get(id); idToRowIndex.put(id, rowIndex); - return componentConnector.getWidget(); + Widget widget = componentConnector.getWidget(); + getLayoutManager().addElementResizeListener(widget.getElement(), + detailsRowResizeListener); + elementToResizeCommand.put(widget.getElement(), + createResizeCommand(rowIndex, widget.getElement())); + + return widget; + } + + private ScheduledCommand createResizeCommand(final int rowIndex, + final Element element) { + return new ScheduledCommand() { + + @Override + public void execute() { + // It should not be possible to get here without calculating + // the spacerCellBorderHeights or without having the details + // row open, nor for this command to be triggered while + // layout is running, but it's safer to check anyway. + if (spacerCellBorderHeights != null + && !getLayoutManager().isLayoutRunning() + && hasDetailsOpen(rowIndex)) { + double height = getLayoutManager().getOuterHeightDouble( + element) + spacerCellBorderHeights; + getWidget().setDetailsHeight(rowIndex, height); + } + } + }; + } + + private boolean hasDetailsOpen(int rowIndex) { + JsonObject row = getWidget().getDataSource().getRow(rowIndex); + if (row.hasKey(GridState.JSONKEY_DETAILS_VISIBLE)) { + String id = row.getString(GridState.JSONKEY_DETAILS_VISIBLE); + return id != null && !id.isEmpty(); + } + return false; } @Override @@ -519,8 +571,16 @@ public class GridConnector extends AbstractHasComponentsConnector getLayoutManager().setNeedsMeasureRecursively(componentConnector); getLayoutManager().layoutNow(); - return getLayoutManager().getOuterHeightDouble( - componentConnector.getWidget().getElement()); + Element element = componentConnector.getWidget().getElement(); + if (spacerCellBorderHeights == null) { + // If theme is changed, new details generator is created from + // scratch, so this value doesn't need to be updated elsewhere. + spacerCellBorderHeights = WidgetUtil + .getBorderTopAndBottomThickness( + element.getParentElement()); + } + + return getLayoutManager().getOuterHeightDouble(element); } /** @@ -568,6 +628,11 @@ public class GridConnector extends AbstractHasComponentsConnector } for (String id : removedDetails) { + Element element = idToDetailsMap.get(id).getWidget() + .getElement(); + elementToResizeCommand.remove(element); + getLayoutManager().removeElementResizeListener(element, + detailsRowResizeListener); idToDetailsMap.remove(id); idToRowIndex.remove(id); } diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java b/compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java index 3efb253e3a..a5e77a0b15 100644 --- a/compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java +++ b/compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java @@ -9110,6 +9110,19 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, } /** + * Update details row height. + * + * @since + * @param rowIndex + * the index of the row for which to update details height + * @param height + * new height of the details row + */ + public void setDetailsHeight(int rowIndex, double height) { + escalator.getBody().setSpacer(rowIndex, height); + } + + /** * Requests that the column widths should be recalculated. * <p> * The actual recalculation is not necessarily done immediately so you diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/GridLayoutDetailsRowResize.java b/uitest/src/main/java/com/vaadin/tests/components/grid/GridLayoutDetailsRowResize.java new file mode 100644 index 0000000000..db4ebd1ae8 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/GridLayoutDetailsRowResize.java @@ -0,0 +1,121 @@ +/* + * Copyright 2000-2017 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.provider.ListDataProvider; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Grid; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.themes.ValoTheme; +import com.vaadin.v7.ui.themes.Reindeer; + +/** + * Tests that details row resizes along with the contents properly. + * + * @author Vaadin Ltd + */ +@SuppressWarnings("deprecation") +public class GridLayoutDetailsRowResize extends SimpleGridUI { + + @Override + protected void setup(VaadinRequest request) { + final Grid<Person> grid = createGrid(); + grid.setSizeFull(); + + addComponent(new Button("Toggle theme", new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + if (ValoTheme.THEME_NAME.equals(getUI().getTheme())) { + getUI().setTheme(Reindeer.THEME_NAME); + } else { + getUI().setTheme(ValoTheme.THEME_NAME); + } + } + })); + + addComponent(grid); + + grid.setDetailsGenerator(item -> { + final GridLayout detailsLayout = new GridLayout(); + detailsLayout.setSizeFull(); + detailsLayout.setHeightUndefined(); + + final Label lbl1 = new Label("test1"); + lbl1.setId("lbl1"); + lbl1.setWidth("200px"); + detailsLayout.addComponent(lbl1); + + final Label lbl2 = new Label("test2"); + lbl2.setId("lbl2"); + detailsLayout.addComponent(lbl2); + + final Label lbl3 = new Label("test3"); + lbl3.setId("lbl3"); + detailsLayout.addComponent(lbl3); + + final Label lbl4 = new Label("test4"); + lbl4.setId("lbl4"); + lbl4.setVisible(false); + detailsLayout.addComponent(lbl4); + + final Button button = new Button("Toggle visibility", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + lbl4.setVisible(!lbl4.isVisible()); + } + }); + button.setId("btn"); + detailsLayout.addComponent(button); + + return detailsLayout; + }); + + grid.addItemClickListener(click -> { + final Person person = click.getItem(); + grid.setDetailsVisible(person, !grid.isDetailsVisible(person)); + }); + + addComponent(new Button("Open details", new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + for (Object itemId : ((ListDataProvider<?>) grid + .getDataProvider()).getItems()) { + if (itemId instanceof Person) { + grid.setDetailsVisible((Person) itemId, true); + } + } + } + })); + } + + @Override + protected String getTestDescription() { + return "Detail row should be correctly resized when its contents change."; + } + + @Override + protected Integer getTicketNumber() { + return 7341; + } +} diff --git a/uitest/src/main/java/com/vaadin/v7/tests/components/grid/GridLayoutDetailsRowResize.java b/uitest/src/main/java/com/vaadin/v7/tests/components/grid/GridLayoutDetailsRowResize.java new file mode 100644 index 0000000000..3c8aac9dcf --- /dev/null +++ b/uitest/src/main/java/com/vaadin/v7/tests/components/grid/GridLayoutDetailsRowResize.java @@ -0,0 +1,136 @@ +/* + * Copyright 2000-2017 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.v7.tests.components.grid; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Component; +import com.vaadin.ui.themes.ValoTheme; +import com.vaadin.v7.event.ItemClickEvent; +import com.vaadin.v7.event.ItemClickEvent.ItemClickListener; +import com.vaadin.v7.ui.Grid; +import com.vaadin.v7.ui.Grid.DetailsGenerator; +import com.vaadin.v7.ui.Grid.RowReference; +import com.vaadin.v7.ui.Label; +import com.vaadin.v7.ui.VerticalLayout; +import com.vaadin.v7.ui.themes.Reindeer; + +/** + * Tests that details row resizes along with the contents properly. + * + * @author Vaadin Ltd + */ +@SuppressWarnings("deprecation") +public class GridLayoutDetailsRowResize extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final Grid grid = new Grid(); + grid.setSizeFull(); + grid.addColumn("name", String.class); + grid.addColumn("born", Integer.class); + + grid.addRow("Nicolaus Copernicus", 1543); + grid.addRow("Galileo Galilei", 1564); + grid.addRow("Johannes Kepler", 1571); + + addComponent(grid); + + grid.setDetailsGenerator(new DetailsGenerator() { + @Override + public Component getDetails(final RowReference rowReference) { + final VerticalLayout detailsLayout = new VerticalLayout(); + detailsLayout.setId("details"); + detailsLayout.setSizeFull(); + detailsLayout.setHeightUndefined(); + + final Label lbl1 = new Label("test1"); + lbl1.setId("lbl1"); + lbl1.setWidth("200px"); + detailsLayout.addComponent(lbl1); + + final Label lbl2 = new Label("test2"); + lbl2.setId("lbl2"); + detailsLayout.addComponent(lbl2); + + final Label lbl3 = new Label("test3"); + lbl3.setId("lbl3"); + detailsLayout.addComponent(lbl3); + + final Label lbl4 = new Label("test4"); + lbl4.setId("lbl4"); + lbl4.setVisible(false); + detailsLayout.addComponent(lbl4); + + final Button button = new Button("Toggle visibility", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + lbl4.setVisible(!lbl4.isVisible()); + } + }); + button.setId("btn"); + detailsLayout.addComponent(button); + + return detailsLayout; + } + }); + + grid.addItemClickListener(new ItemClickListener() { + @Override + public void itemClick(final ItemClickEvent event) { + final Object itemId = event.getItemId(); + grid.setDetailsVisible(itemId, !grid.isDetailsVisible(itemId)); + } + }); + + addComponent(new Button("Toggle theme", new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + if (ValoTheme.THEME_NAME.equals(getUI().getTheme())) { + getUI().setTheme(Reindeer.THEME_NAME); + } else { + getUI().setTheme(ValoTheme.THEME_NAME); + } + } + })); + + addComponent(new Button("Open details", new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + for (Object itemId : grid.getContainerDataSource() + .getItemIds()) { + grid.setDetailsVisible(itemId, true); + } + } + })); + } + + @Override + protected String getTestDescription() { + return "Detail row should be correctly resized when its contents change."; + } + + @Override + protected Integer getTicketNumber() { + return 7341; + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/GridLayoutDetailsRowResizeTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/GridLayoutDetailsRowResizeTest.java new file mode 100644 index 0000000000..d0a7bc7f6b --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/grid/GridLayoutDetailsRowResizeTest.java @@ -0,0 +1,193 @@ +/* + * Copyright 2000-2017 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 static org.hamcrest.number.IsCloseTo.closeTo; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.elements.LabelElement; +import com.vaadin.testbench.parallel.Browser; +import com.vaadin.testbench.parallel.TestCategory; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Tests that details row resizes along with the contents properly. + * + * @author Vaadin Ltd + */ +@TestCategory("grid") +public class GridLayoutDetailsRowResizeTest extends MultiBrowserTest { + + @Test + public void testLabelHeights() { + openTestURL(); + waitForElementPresent(By.className("v-grid")); + + GridElement grid = $(GridElement.class).first(); + + grid.getCell(2, 0).click(); + waitForElementPresent(By.id("lbl2")); + + WebElement layout = grid.findElement(By.className("v-gridlayout")); + int layoutHeight = layout.getSize().height; + + ButtonElement button = $(ButtonElement.class).id("btn"); + int buttonHeight = button.getSize().height; + + // height should be divided equally + double expectedLabelHeight = (layoutHeight - buttonHeight) / 3; + assertLabelHeight("lbl1", expectedLabelHeight); + assertLabelHeight("lbl2", expectedLabelHeight); + assertLabelHeight("lbl3", expectedLabelHeight); + + assertDetailsRowHeight(layoutHeight); + + // ensure fourth label isn't present yet + assertElementNotPresent(By.id("lbl4")); + + button.click(); + waitForElementPresent(By.id("lbl4")); + + // get layout height after the new label has been added + layoutHeight = layout.getSize().height; + + expectedLabelHeight = (layoutHeight - buttonHeight) / 4; + assertLabelHeight("lbl1", expectedLabelHeight); + assertLabelHeight("lbl2", expectedLabelHeight); + assertLabelHeight("lbl3", expectedLabelHeight); + assertLabelHeight("lbl4", expectedLabelHeight); + + assertDetailsRowHeight(layoutHeight); + } + + @Test + public void testMultipleDetailsRows() { + if (Browser.PHANTOMJS.name() + .equalsIgnoreCase(getDesiredCapabilities().getBrowserName())) { + // For some inexplicable reason PhantomJS fails to click that + // button, even if similar button clicks work just fine in other + // tests. Didn't disable PhantomJS altogether so that the other test + // at least could work in the initial pre-merge regression check. + return; + } + + setDebug(true); + openTestURL(); + waitForElementPresent(By.className("v-grid")); + + // all rows won't fit if using Valo, toggle back to reindeer + ButtonElement themeButton = $(ButtonElement.class) + .caption("Toggle theme").first(); + int buttonHeight = themeButton.getSize().height; + + themeButton.click(); + + // wait for the theme change to take hold + waitUntil(new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver arg0) { + return buttonHeight > $(ButtonElement.class) + .caption("Toggle theme").first().getSize().height; + } + + @Override + public String toString() { + // Expected condition failed: waiting for ... + return "button's theme to change"; + } + }); + + ButtonElement detailsButton = $(ButtonElement.class) + .caption("Open details").first(); + + detailsButton.click(); + waitForElementPresent(By.id("lbl2")); + + List<ButtonElement> buttons = $(ButtonElement.class) + .caption("Toggle visibility").all(); + assertThat("Unexpected amount of details rows.", buttons.size(), is(3)); + + Map<ButtonElement, Integer> positions = new LinkedHashMap<ButtonElement, Integer>(); + Map<Integer, ButtonElement> ordered = new TreeMap<Integer, ButtonElement>(); + for (ButtonElement button : buttons) { + positions.put(button, button.getLocation().getY()); + ordered.put(button.getLocation().getY(), button); + } + int labelHeight = 0; + for (LabelElement label : $(LabelElement.class).all()) { + if ("test1".equals(label.getText())) { + labelHeight = label.getSize().height; + } + } + + // toggle the contents + for (ButtonElement button : buttons) { + button.click(); + } + + int i = 0; + for (Entry<Integer, ButtonElement> entry : ordered.entrySet()) { + ++i; + ButtonElement button = entry.getValue(); + assertThat( + String.format("Unexpected button position: details row %s.", + i), + (double) button.getLocation().getY(), + closeTo(positions.get(button) + (i * labelHeight), 1d)); + } + + // toggle the contents + for (ButtonElement button : buttons) { + button.click(); + } + + // assert original positions back + for (ButtonElement button : buttons) { + assertThat(String.format("Unexpected button position."), + (double) button.getLocation().getY(), + closeTo(positions.get(button), 1d)); + } + } + + private void assertLabelHeight(String id, double expectedHeight) { + // 1px leeway for calculations + assertThat("Unexpected label height.", + (double) $(LabelElement.class).id(id).getSize().height, + closeTo(expectedHeight, 1d)); + } + + private void assertDetailsRowHeight(int layoutHeight) { + // check that details row height matches layout height (3px leeway) + WebElement detailsRow = findElement(By.className("v-grid-spacer")); + assertThat("Unexpected details row height", (double) layoutHeight, + closeTo(detailsRow.getSize().height, 3d)); + } +} diff --git a/uitest/src/test/java/com/vaadin/v7/tests/components/grid/GridLayoutDetailsRowResizeTest.java b/uitest/src/test/java/com/vaadin/v7/tests/components/grid/GridLayoutDetailsRowResizeTest.java new file mode 100644 index 0000000000..21bc766d59 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/v7/tests/components/grid/GridLayoutDetailsRowResizeTest.java @@ -0,0 +1,160 @@ +/* + * Copyright 2000-2017 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.v7.tests.components.grid; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.number.IsCloseTo.closeTo; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.elements.LabelElement; +import com.vaadin.testbench.elements.VerticalLayoutElement; +import com.vaadin.testbench.parallel.TestCategory; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Tests that details row resizes along with the contents properly. + * + * @author Vaadin Ltd + */ +@TestCategory("grid") +public class GridLayoutDetailsRowResizeTest extends MultiBrowserTest { + + @Test + public void testLabelHeights() { + openTestURL(); + waitForElementPresent(By.className("v-grid")); + + GridElement grid = $(GridElement.class).first(); + + grid.getCell(2, 0).click(); + waitForElementPresent(By.id("lbl2")); + + VerticalLayoutElement layout = $(VerticalLayoutElement.class) + .id("details"); + int layoutHeight = layout.getSize().height; + + ButtonElement button = $(ButtonElement.class).id("btn"); + int buttonHeight = button.getSize().height; + + // height should be divided equally + double expectedLabelHeight = (layoutHeight - buttonHeight) / 3; + assertLabelHeight("lbl1", expectedLabelHeight); + assertLabelHeight("lbl2", expectedLabelHeight); + assertLabelHeight("lbl3", expectedLabelHeight); + + assertDetailsRowHeight(layoutHeight); + + // ensure fourth label isn't present yet + assertElementNotPresent(By.id("lbl4")); + + button.click(); + waitForElementPresent(By.id("lbl4")); + + // get layout height after the new label has been added + layoutHeight = layout.getSize().height; + + expectedLabelHeight = (layoutHeight - buttonHeight) / 4; + assertLabelHeight("lbl1", expectedLabelHeight); + assertLabelHeight("lbl2", expectedLabelHeight); + assertLabelHeight("lbl3", expectedLabelHeight); + assertLabelHeight("lbl4", expectedLabelHeight); + + assertDetailsRowHeight(layoutHeight); + } + + @Test + public void testMultipleDetailsRows() { + openTestURL(); + waitForElementPresent(By.className("v-grid")); + + ButtonElement detailsButton = $(ButtonElement.class) + .caption("Open details").first(); + + detailsButton.click(); + waitForElementPresent(By.id("lbl2")); + + List<ButtonElement> buttons = $(ButtonElement.class) + .caption("Toggle visibility").all(); + assertThat("Unexpected amount of details rows.", buttons.size(), is(3)); + + Map<ButtonElement, Integer> positions = new LinkedHashMap<ButtonElement, Integer>(); + Map<Integer, ButtonElement> ordered = new TreeMap<Integer, ButtonElement>(); + for (ButtonElement button : buttons) { + positions.put(button, button.getLocation().getY()); + ordered.put(button.getLocation().getY(), button); + } + int labelHeight = 0; + for (LabelElement label : $(LabelElement.class).all()) { + if ("test1".equals(label.getText())) { + labelHeight = label.getSize().height; + } + } + + // toggle the contents + for (ButtonElement button : buttons) { + button.click(); + } + + int i = 0; + for (Entry<Integer, ButtonElement> entry : ordered.entrySet()) { + ++i; + ButtonElement button = entry.getValue(); + assertThat( + String.format("Unexpected button position: details row %s.", + i), + (double) button.getLocation().getY(), + closeTo(positions.get(button) + (i * labelHeight), 1d)); + } + + // toggle the contents + for (ButtonElement button : buttons) { + button.click(); + } + + // assert original positions back + for (ButtonElement button : buttons) { + assertThat(String.format("Unexpected button position."), + (double) button.getLocation().getY(), + closeTo(positions.get(button), 1d)); + } + } + + private void assertLabelHeight(String id, double expectedHeight) { + // 1px leeway for calculations + assertThat("Unexpected label height.", + (double) $(LabelElement.class).id(id).getSize().height, + closeTo(expectedHeight, 1d)); + } + + private void assertDetailsRowHeight(int layoutHeight) { + // check that details row height matches layout height (1px leeway) + WebElement detailsRow = findElement(By.className("v-grid-spacer")); + assertThat("Unexpected details row height", (double) layoutHeight, + closeTo(detailsRow.getSize().height, 1d)); + } +} |