summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnsku <Ansku@users.noreply.github.com>2017-08-22 14:59:49 +0300
committerAleksi Hietanen <aleksi@vaadin.com>2017-08-22 14:59:49 +0300
commit3b2bea5236718fb13c9885141c0a4dddb323a868 (patch)
treec701551cf723e5ca4424574f96db627fb3457b14
parent5ef925daa91b1253f170f244e2a992f4f92979e1 (diff)
downloadvaadin-framework-3b2bea5236718fb13c9885141c0a4dddb323a868.tar.gz
vaadin-framework-3b2bea5236718fb13c9885141c0a4dddb323a868.zip
Resize should work within Grid details row (#9808)
Fixes #7341
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/DetailsManagerConnector.java79
-rwxr-xr-xclient/src/main/java/com/vaadin/client/widgets/Grid.java13
-rw-r--r--compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java73
-rw-r--r--compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java13
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/grid/GridLayoutDetailsRowResize.java121
-rw-r--r--uitest/src/main/java/com/vaadin/v7/tests/components/grid/GridLayoutDetailsRowResize.java136
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/grid/GridLayoutDetailsRowResizeTest.java193
-rw-r--r--uitest/src/test/java/com/vaadin/v7/tests/components/grid/GridLayoutDetailsRowResizeTest.java160
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));
+ }
+}