summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnna Koskinen <anna@vaadin.com>2016-06-01 11:56:34 +0300
committerJohannes Dahlström <johannesd@vaadin.com>2016-06-29 12:43:16 +0000
commitedad7348bb8eba807225bfa72d4b0a4342426c71 (patch)
tree4eefaf917c8ef6ab7c7c250597de32b94c8a4fe5
parent75b282c319b2783d0ea2737727081c6923342ac0 (diff)
downloadvaadin-framework-edad7348bb8eba807225bfa72d4b0a4342426c71.tar.gz
vaadin-framework-edad7348bb8eba807225bfa72d4b0a4342426c71.zip
Updates to Grid's height handling (#19690).
- new height more for undefined height that works like in Table and resizes the grid when details row opens or closes Change-Id: I2dc817140308093865be30de72edcd6494e4a44b
-rw-r--r--client/src/main/java/com/vaadin/client/widgets/Escalator.java38
-rw-r--r--client/src/main/java/com/vaadin/client/widgets/Grid.java8
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/grid/HeightMode.java8
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/grid/GridHeight.java189
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/grid/GridHeightTest.java199
5 files changed, 436 insertions, 6 deletions
diff --git a/client/src/main/java/com/vaadin/client/widgets/Escalator.java b/client/src/main/java/com/vaadin/client/widgets/Escalator.java
index 29b7eb6d53..25e83592d7 100644
--- a/client/src/main/java/com/vaadin/client/widgets/Escalator.java
+++ b/client/src/main/java/com/vaadin/client/widgets/Escalator.java
@@ -1148,6 +1148,9 @@ public class Escalator extends Widget implements RequiresResize,
assertArgumentsAreValidAndWithinRange(index, numberOfRows);
rows -= numberOfRows;
+ if (heightMode == HeightMode.UNDEFINED) {
+ heightByRows = rows;
+ }
if (!isAttached()) {
return;
@@ -1271,6 +1274,9 @@ public class Escalator extends Widget implements RequiresResize,
}
rows += numberOfRows;
+ if (heightMode == HeightMode.UNDEFINED) {
+ heightByRows = rows;
+ }
/*
* only add items in the DOM if the widget itself is attached to the
@@ -5826,7 +5832,13 @@ public class Escalator extends Widget implements RequiresResize,
if (height != null && !height.isEmpty()) {
heightByCss = height;
} else {
- heightByCss = DEFAULT_HEIGHT;
+ if (getHeightMode() == HeightMode.UNDEFINED) {
+ heightByRows = body.getRowCount();
+ applyHeightByRows();
+ return;
+ } else {
+ heightByCss = DEFAULT_HEIGHT;
+ }
}
if (getHeightMode() == HeightMode.CSS) {
@@ -5840,7 +5852,16 @@ public class Escalator extends Widget implements RequiresResize,
if (height != null && !height.isEmpty()) {
super.setHeight(height);
} else {
- super.setHeight(DEFAULT_HEIGHT);
+ if (getHeightMode() == HeightMode.UNDEFINED) {
+ int newHeightByRows = body.getRowCount();
+ if (heightByRows != newHeightByRows) {
+ heightByRows = newHeightByRows;
+ applyHeightByRows();
+ }
+ return;
+ } else {
+ super.setHeight(DEFAULT_HEIGHT);
+ }
}
recalculateElementSizes();
@@ -6318,7 +6339,7 @@ public class Escalator extends Widget implements RequiresResize,
* define its height that way.
*/
private void applyHeightByRows() {
- if (heightMode != HeightMode.ROW) {
+ if (heightMode != HeightMode.ROW && heightMode != HeightMode.UNDEFINED) {
return;
}
@@ -6327,9 +6348,13 @@ public class Escalator extends Widget implements RequiresResize,
double bodyHeight = body.getDefaultRowHeight() * heightByRows;
double scrollbar = horizontalScrollbar.showsScrollHandle() ? horizontalScrollbar
.getScrollbarThickness() : 0;
+ double spacerHeight = 0; // ignored if HeightMode.ROW
+ if (heightMode == HeightMode.UNDEFINED) {
+ spacerHeight = body.spacerContainer.getSpacerHeightsSum();
+ }
- double totalHeight = headerHeight + bodyHeight + scrollbar
- + footerHeight;
+ double totalHeight = headerHeight + bodyHeight + spacerHeight
+ + scrollbar + footerHeight;
setHeightInternal(totalHeight + "px");
}
@@ -6370,6 +6395,9 @@ public class Escalator extends Widget implements RequiresResize,
case ROW:
setHeightByRows(heightByRows);
break;
+ case UNDEFINED:
+ setHeightByRows(body.getRowCount());
+ break;
default:
throw new IllegalStateException("Unimplemented feature "
+ "- unknown HeightMode: " + this.heightMode);
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 93aeac0d68..7665111416 100644
--- a/client/src/main/java/com/vaadin/client/widgets/Grid.java
+++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java
@@ -3600,6 +3600,9 @@ public class Grid<T> extends ResizeComposite implements
}
escalator.getBody().setSpacer(rowIndex, spacerHeight);
+ if (getHeightMode() == HeightMode.UNDEFINED) {
+ setHeightByRows(getEscalator().getBody().getRowCount());
+ }
}
@Override
@@ -3628,6 +3631,11 @@ public class Grid<T> extends ResizeComposite implements
setParent(detailsWidget, null);
spacerElement.removeAllChildren();
+ if (getHeightMode() == HeightMode.UNDEFINED) {
+ // update spacer height
+ escalator.getBody().setSpacer(spacer.getRow(), 0);
+ setHeightByRows(getEscalator().getBody().getRowCount());
+ }
}
}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/HeightMode.java b/shared/src/main/java/com/vaadin/shared/ui/grid/HeightMode.java
index 4cd19a01b1..7fc992566f 100644
--- a/shared/src/main/java/com/vaadin/shared/ui/grid/HeightMode.java
+++ b/shared/src/main/java/com/vaadin/shared/ui/grid/HeightMode.java
@@ -38,5 +38,11 @@ public enum HeightMode {
* The height of the Component or Widget in question is defined by a number
* of rows.
*/
- ROW;
+ ROW,
+
+ /**
+ * The height of the Component or Widget in question is defined by its
+ * contents.
+ */
+ UNDEFINED;
}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/GridHeight.java b/uitest/src/main/java/com/vaadin/tests/components/grid/GridHeight.java
new file mode 100644
index 0000000000..c22bc56103
--- /dev/null
+++ b/uitest/src/main/java/com/vaadin/tests/components/grid/GridHeight.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2000-2016 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.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.event.ItemClickEvent;
+import com.vaadin.event.ItemClickEvent.ItemClickListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.grid.HeightMode;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.DetailsGenerator;
+import com.vaadin.ui.Grid.RowReference;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.OptionGroup;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * Tests that Grid gets correct height based on height mode, and resizes
+ * properly with details row if height is undefined.
+ *
+ * @author Vaadin Ltd
+ */
+public class GridHeight extends AbstractTestUI {
+
+ static final String FULL = "Full";
+ static final String UNDEFINED = "Undefined";
+ static final String PX100 = "100px";
+ static final Integer ROW3 = 3;
+
+ static final Object[] gridHeights = { FULL, UNDEFINED, ROW3 };
+ static final String[] gridWidths = { FULL, UNDEFINED };
+ static final String[] detailsRowHeights = { FULL, UNDEFINED, PX100 };
+
+ private Grid grid;
+ private Map<Object, VerticalLayout> detailsLayouts = new HashMap<Object, VerticalLayout>();
+ private OptionGroup detailsHeightSelector;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+
+ grid = new Grid();
+ grid.addColumn("name", String.class);
+ grid.addColumn("born", Integer.class);
+
+ grid.addRow("Nicolaus Copernicus", 1543);
+ grid.addRow("Galileo Galilei", 1564);
+ for (int i = 0; i < 1; ++i) {
+ grid.addRow("Johannes Kepler", 1571);
+ }
+
+ grid.setDetailsGenerator(new DetailsGenerator() {
+ @Override
+ public Component getDetails(final RowReference rowReference) {
+ if (!detailsLayouts.containsKey(rowReference.getItemId())) {
+ createDetailsLayout(rowReference.getItemId());
+ }
+ return detailsLayouts.get(rowReference.getItemId());
+ }
+ });
+
+ grid.addItemClickListener(new ItemClickListener() {
+ @Override
+ public void itemClick(final ItemClickEvent event) {
+ final Object itemId = event.getItemId();
+ grid.setDetailsVisible(itemId, !grid.isDetailsVisible(itemId));
+ }
+ });
+
+ addComponent(createOptionLayout());
+ addComponent(grid);
+ }
+
+ private void createDetailsLayout(Object itemId) {
+ VerticalLayout detailsLayout = new VerticalLayout();
+ setDetailsHeight(detailsLayout, detailsHeightSelector.getValue());
+ detailsLayout.setWidth("100%");
+
+ Label lbl1 = new Label("details row");
+ lbl1.setId("lbl1");
+ lbl1.setSizeUndefined();
+ detailsLayout.addComponent(lbl1);
+ detailsLayout.setComponentAlignment(lbl1, Alignment.MIDDLE_CENTER);
+
+ detailsLayouts.put(itemId, detailsLayout);
+ }
+
+ private Component createOptionLayout() {
+ HorizontalLayout optionLayout = new HorizontalLayout();
+ OptionGroup gridHeightSelector = new OptionGroup("Grid height",
+ Arrays.<Object> asList(gridHeights));
+ gridHeightSelector.setId("gridHeightSelector");
+ gridHeightSelector.setItemCaption(ROW3, ROW3 + " rows");
+ gridHeightSelector.addValueChangeListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ Object value = event.getProperty().getValue();
+ if (UNDEFINED.equals(value)) {
+ grid.setHeightUndefined();
+ grid.setHeightMode(HeightMode.UNDEFINED);
+ } else if (FULL.equals(value)) {
+ grid.setHeight("100%");
+ grid.setHeightMode(HeightMode.CSS);
+ } else if (ROW3.equals(value)) {
+ grid.setHeightByRows(ROW3);
+ grid.setHeightMode(HeightMode.ROW);
+ }
+ }
+ });
+ gridHeightSelector.setValue(UNDEFINED);
+ optionLayout.addComponent(gridHeightSelector);
+
+ OptionGroup gridWidthSelector = new OptionGroup("Grid width",
+ Arrays.asList(gridWidths));
+ gridWidthSelector.setId("gridWidthSelector");
+ gridWidthSelector.addValueChangeListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ Object value = event.getProperty().getValue();
+ if (UNDEFINED.equals(value)) {
+ grid.setWidthUndefined();
+ } else if (FULL.equals(value)) {
+ grid.setWidth("100%");
+ }
+ }
+ });
+ gridWidthSelector.setValue(UNDEFINED);
+ optionLayout.addComponent(gridWidthSelector);
+
+ detailsHeightSelector = new OptionGroup("Details row height",
+ Arrays.asList(detailsRowHeights));
+ detailsHeightSelector.setId("detailsHeightSelector");
+ detailsHeightSelector.addValueChangeListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ Object value = event.getProperty().getValue();
+ for (VerticalLayout detailsLayout : detailsLayouts.values()) {
+ setDetailsHeight(detailsLayout, value);
+ }
+ }
+ });
+ detailsHeightSelector.setValue(PX100);
+ optionLayout.addComponent(detailsHeightSelector);
+ return optionLayout;
+ }
+
+ private void setDetailsHeight(VerticalLayout detailsLayout, Object value) {
+ if (UNDEFINED.equals(value)) {
+ detailsLayout.setHeightUndefined();
+ } else if (FULL.equals(value)) {
+ detailsLayout.setHeight("100%");
+ } else if (PX100.equals(value)) {
+ detailsLayout.setHeight(PX100);
+ }
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Grid with undefined height should display all rows and resize when details row is opened."
+ + "<br>Grid with full height is always 400px high regardless or details row."
+ + "<br>Grid with row height should always be the height of those rows regardless of details row.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 19690;
+ }
+}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/GridHeightTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/GridHeightTest.java
new file mode 100644
index 0000000000..14ad0224d6
--- /dev/null
+++ b/uitest/src/test/java/com/vaadin/tests/components/grid/GridHeightTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2000-2016 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.Matchers.is;
+import static org.hamcrest.number.IsCloseTo.closeTo;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.remote.DesiredCapabilities;
+
+import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.testbench.elements.OptionGroupElement;
+import com.vaadin.testbench.parallel.BrowserUtil;
+import com.vaadin.testbench.parallel.TestCategory;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+/**
+ * Tests that Grid gets correct height based on height mode, and resizes
+ * properly with details row if height is undefined.
+ *
+ * @author Vaadin Ltd
+ */
+@TestCategory("grid")
+public class GridHeightTest extends MultiBrowserTest {
+
+ @Override
+ public void setup() throws Exception {
+ super.setup();
+ openTestURL();
+ waitForElementPresent(By.className("v-grid"));
+ }
+
+ @Test
+ public void testGridHeightAndResizingUndefined()
+ throws InterruptedException {
+ assertNoErrors(testGridHeightAndResizing(GridHeight.UNDEFINED));
+ }
+
+ @Test
+ public void testGridHeightAndResizingRow() throws InterruptedException {
+ if (isIE8orIE9()) {
+ /*
+ * with IE8 and IE9 and this height mode grid resizes when it
+ * shouldn't and doesn't resize when it should, pre-existing problem
+ * that isn't within the scope of this ticket
+ */
+ return;
+ }
+ assertNoErrors(testGridHeightAndResizing(GridHeight.ROW3));
+ }
+
+ @Test
+ public void testGridHeightAndResizingFull() throws InterruptedException {
+ assertNoErrors(testGridHeightAndResizing(GridHeight.FULL));
+ }
+
+ private Map<AssertionError, Object[]> testGridHeightAndResizing(
+ Object gridHeight) throws InterruptedException {
+ Map<AssertionError, Object[]> errors = new HashMap<AssertionError, Object[]>();
+ String caption;
+ if (GridHeight.ROW3.equals(gridHeight)) {
+ caption = gridHeight + " rows";
+ } else {
+ caption = (String) gridHeight;
+ }
+ $(OptionGroupElement.class).id("gridHeightSelector").selectByText(
+ caption);
+ for (String gridWidth : GridHeight.gridWidths) {
+ $(OptionGroupElement.class).id("gridWidthSelector").selectByText(
+ gridWidth);
+ for (String detailsRowHeight : GridHeight.detailsRowHeights) {
+ $(OptionGroupElement.class).id("detailsHeightSelector")
+ .selectByText(detailsRowHeight);
+ sleep(500);
+
+ GridElement grid = $(GridElement.class).first();
+ int initialHeight = grid.getSize().getHeight();
+ try {
+ // check default height
+ assertGridHeight(getExpectedInitialHeight(gridHeight),
+ initialHeight);
+ } catch (AssertionError e) {
+ errors.put(e, new Object[] { gridHeight, gridWidth,
+ detailsRowHeight, "initial" });
+ }
+
+ grid.getRow(2).click(5, 5);
+ waitForElementPresent(By.id("lbl1"));
+
+ int openHeight = grid.getSize().getHeight();
+ try {
+ // check height with details row opened
+ assertGridHeight(
+ getExpectedOpenedHeight(gridHeight,
+ detailsRowHeight), openHeight);
+ } catch (AssertionError e) {
+ errors.put(e, new Object[] { gridHeight, gridWidth,
+ detailsRowHeight, "opened" });
+ }
+
+ grid.getRow(2).click(5, 5);
+ waitForElementNotPresent(By.id("lbl1"));
+
+ int afterHeight = grid.getSize().getHeight();
+ try {
+ // check height with details row closed again
+ assertThat("Unexpected Grid Height", afterHeight,
+ is(initialHeight));
+ } catch (AssertionError e) {
+ errors.put(e, new Object[] { gridHeight, gridWidth,
+ detailsRowHeight, "closed" });
+ }
+ }
+ }
+ return errors;
+ }
+
+ private void assertNoErrors(Map<AssertionError, Object[]> errors) {
+ if (!errors.isEmpty()) {
+ StringBuilder sb = new StringBuilder("Exceptions: ");
+ for (Entry<AssertionError, Object[]> entry : errors.entrySet()) {
+ sb.append("\n");
+ for (Object value : entry.getValue()) {
+ sb.append(value);
+ sb.append(" - ");
+ }
+ sb.append(entry.getKey().getMessage());
+ }
+ Assert.fail(sb.toString());
+ }
+ }
+
+ private int getExpectedInitialHeight(Object gridHeight) {
+ int result = 0;
+ if (GridHeight.UNDEFINED.equals(gridHeight)
+ || GridHeight.ROW3.equals(gridHeight)) {
+ result = 81;
+ } else if (GridHeight.FULL.equals(gridHeight)) {
+ // pre-existing issue
+ result = 400;
+ }
+ return result;
+ }
+
+ private int getExpectedOpenedHeight(Object gridHeight,
+ Object detailsRowHeight) {
+ int result = 0;
+ if (GridHeight.UNDEFINED.equals(gridHeight)) {
+ if (GridHeight.PX100.equals(detailsRowHeight)) {
+ result = 182;
+ } else if (GridHeight.FULL.equals(detailsRowHeight)) {
+ if (isIE8orIE9()) {
+ // pre-existing bug in IE8 & IE9, details row doesn't layout
+ // itself properly
+ result = 100;
+ } else {
+ result = 131;
+ }
+ } else if (GridHeight.UNDEFINED.equals(detailsRowHeight)) {
+ result = 100;
+ }
+ } else if (GridHeight.ROW3.equals(gridHeight)
+ || GridHeight.FULL.equals(gridHeight)) {
+ result = getExpectedInitialHeight(gridHeight);
+ }
+ return result;
+ }
+
+ private boolean isIE8orIE9() {
+ DesiredCapabilities desiredCapabilities = getDesiredCapabilities();
+ return BrowserUtil.isIE8(desiredCapabilities)
+ || BrowserUtil.isIE(desiredCapabilities, 9);
+ }
+
+ private void assertGridHeight(int expected, int actual) {
+ assertThat("Unexpected Grid Height", (double) actual,
+ closeTo(expected, 1));
+ }
+}