Browse Source

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
feature/vaadin8-book-vol2
Anna Koskinen 8 years ago
parent
commit
f5f45293b9

+ 33
- 5
client/src/main/java/com/vaadin/client/widgets/Escalator.java View File

@@ -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);

+ 8
- 0
client/src/main/java/com/vaadin/client/widgets/Grid.java View File

@@ -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());
}
}
}


+ 7
- 1
shared/src/main/java/com/vaadin/shared/ui/grid/HeightMode.java View File

@@ -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;
}

+ 189
- 0
uitest/src/main/java/com/vaadin/tests/components/grid/GridHeight.java View File

@@ -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;
}
}

+ 199
- 0
uitest/src/test/java/com/vaadin/tests/components/grid/GridHeightTest.java View File

@@ -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));
}
}

Loading…
Cancel
Save