import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.GridServerRpc;
+import com.vaadin.shared.ui.grid.GridState;
import elemental.json.JsonObject;
return ensureHandlerManager()
.addHandler(ConnectorHierarchyChangeEvent.TYPE, handler);
}
+
+ @Override
+ public GridState getState() {
+ return (GridState) super.getState();
+ }
}
import com.vaadin.shared.ui.grid.GridConstants.Section;
import com.vaadin.shared.ui.grid.GridServerRpc;
import com.vaadin.shared.ui.grid.GridState;
+import com.vaadin.shared.ui.grid.HeightMode;
import elemental.json.Json;
import elemental.json.JsonObject;
return Collections.unmodifiableSet(extensionComponents).iterator();
}
+ /**
+ * Sets the number of frozen columns in this grid. Setting the count to 0
+ * means that no data columns will be frozen, but the built-in selection
+ * checkbox column will still be frozen if it's in use. Setting the count to
+ * -1 will also disable the selection column.
+ * <p>
+ * The default value is 0.
+ *
+ * @param numberOfColumns
+ * the number of columns that should be frozen
+ *
+ * @throws IllegalArgumentException
+ * if the column count is less than -1 or greater than the
+ * number of visible columns
+ */
+ public void setFrozenColumnCount(int numberOfColumns) {
+ if (numberOfColumns < -1 || numberOfColumns > columnSet.size()) {
+ throw new IllegalArgumentException(
+ "count must be between -1 and the current number of columns ("
+ + columnSet.size() + "): " + numberOfColumns);
+ }
+
+ getState().frozenColumnCount = numberOfColumns;
+ }
+
+ /**
+ * Gets the number of frozen columns in this grid. 0 means that no data
+ * columns will be frozen, but the built-in selection checkbox column will
+ * still be frozen if it's in use. -1 means that not even the selection
+ * column is frozen.
+ * <p>
+ * <em>NOTE:</em> this count includes {@link Column#isHidden() hidden
+ * columns} in the count.
+ *
+ * @see #setFrozenColumnCount(int)
+ *
+ * @return the number of frozen columns
+ */
+ public int getFrozenColumnCount() {
+ return getState(false).frozenColumnCount;
+ }
+
+ /**
+ * Sets the number of rows that should be visible in Grid's body. This
+ * method will set the height mode to be {@link HeightMode#ROW}.
+ *
+ * @param rows
+ * The height in terms of number of rows displayed in Grid's
+ * body. If Grid doesn't contain enough rows, white space is
+ * displayed instead. If <code>null</code> is given, then Grid's
+ * height is undefined
+ * @throws IllegalArgumentException
+ * if {@code rows} is zero or less
+ * @throws IllegalArgumentException
+ * if {@code rows} is {@link Double#isInfinite(double) infinite}
+ * @throws IllegalArgumentException
+ * if {@code rows} is {@link Double#isNaN(double) NaN}
+ */
+ public void setHeightByRows(double rows) {
+ if (rows <= 0.0d) {
+ throw new IllegalArgumentException(
+ "More than zero rows must be shown.");
+ } else if (Double.isInfinite(rows)) {
+ throw new IllegalArgumentException(
+ "Grid doesn't support infinite heights");
+ } else if (Double.isNaN(rows)) {
+ throw new IllegalArgumentException("NaN is not a valid row count");
+ }
+ getState().heightMode = HeightMode.ROW;
+ getState().heightByRows = rows;
+ }
+
+ /**
+ * Gets the amount of rows in Grid's body that are shown, while
+ * {@link #getHeightMode()} is {@link HeightMode#ROW}.
+ *
+ * @return the amount of rows that are being shown in Grid's body
+ * @see #setHeightByRows(double)
+ */
+ public double getHeightByRows() {
+ return getState(false).heightByRows;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * <em>Note:</em> This method will set the height mode to be
+ * {@link HeightMode#CSS}.
+ *
+ * @see #setHeightMode(HeightMode)
+ */
+ @Override
+ public void setHeight(float height, Unit unit) {
+ getState().heightMode = HeightMode.CSS;
+ super.setHeight(height, unit);
+ }
+
+ /**
+ * Defines the mode in which the Grid widget's height is calculated.
+ * <p>
+ * If {@link HeightMode#CSS} is given, Grid will respect the values given
+ * via a {@code setHeight}-method, and behave as a traditional Component.
+ * <p>
+ * If {@link HeightMode#ROW} is given, Grid will make sure that the body
+ * will display as many rows as {@link #getHeightByRows()} defines.
+ * <em>Note:</em> If headers/footers are inserted or removed, the widget
+ * will resize itself to still display the required amount of rows in its
+ * body. It also takes the horizontal scrollbar into account.
+ *
+ * @param heightMode
+ * the mode in to which Grid should be set
+ */
+ public void setHeightMode(HeightMode heightMode) {
+ /*
+ * This method is a workaround for the fact that Vaadin re-applies
+ * widget dimensions (height/width) on each state change event. The
+ * original design was to have setHeight and setHeightByRow be equals,
+ * and whichever was called the latest was considered in effect.
+ *
+ * But, because of Vaadin always calling setHeight on the widget, this
+ * approach doesn't work.
+ */
+
+ getState().heightMode = heightMode;
+ }
+
+ /**
+ * Returns the current {@link HeightMode} the Grid is in.
+ * <p>
+ * Defaults to {@link HeightMode#CSS}.
+ *
+ * @return the current HeightMode
+ */
+ public HeightMode getHeightMode() {
+ return getState(false).heightMode;
+ }
+
+ @Override
+ protected GridState getState() {
+ return getState(true);
+ }
+
+ @Override
+ protected GridState getState(boolean markAsDirty) {
+ return (GridState) super.getState(markAsDirty);
+ }
+
private void addExtensionComponent(Component c) {
if (extensionComponents.add(c)) {
c.setParent(this);
+++ /dev/null
-package com.vaadin.tests.components.grid;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.vaadin.ui.Component;
-import com.vaadin.ui.Grid;
-import com.vaadin.ui.Label;
-
-public class GridDetailsTest {
-
- private final class DummyLabel extends Label {
- private DummyLabel(String content) {
- super(content);
- }
-
- @Override
- public String getConnectorId() {
- return "";
- }
- }
-
- public static class TestGrid extends Grid<String> {
-
- /**
- * Used to execute data generation
- */
- public void runDataGeneration() {
- super.getDataCommunicator().beforeClientResponse(true);
- }
- }
-
- private TestGrid grid;
- private List<String> data;
-
- @Before
- public void setUp() {
- grid = new TestGrid();
- // Setup Grid and generate some details
- data = new ArrayList<>(Arrays.asList("Foo", "Bar"));
- grid.setItems(data);
- grid.setDetailsGenerator(s -> new DummyLabel(s));
-
- data.forEach(s -> grid.setDetailsVisible(s, true));
-
- grid.runDataGeneration();
- }
-
- @Test
- public void testGridComponentIteratorContainsDetailsComponents() {
- Iterator<Component> i = grid.iterator();
-
- while (i.hasNext()) {
- Component c = i.next();
- if (c instanceof Label) {
- String value = ((Label) c).getValue();
- Assert.assertTrue(
- "Unexpected label in component iterator with value "
- + value,
- data.remove(value));
- } else {
- Assert.fail(
- "Iterator contained a component that is not a label.");
- }
- }
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void testGridComponentIteratorNotModifiable() {
- Iterator<Component> iterator = grid.iterator();
- iterator.next();
- // This should fail
- iterator.remove();
- }
-
- @Test
- public void testGridComponentIteratorIsEmptyAfterHidingDetails() {
- Assert.assertTrue("Component iterator should have components.",
- grid.iterator().hasNext());
- data.forEach(s -> grid.setDetailsVisible(s, false));
- Assert.assertFalse("Component iterator should not have components.",
- grid.iterator().hasNext());
- }
-}
--- /dev/null
+package com.vaadin.tests.server.component.grid;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Label;
+
+public class GridDetailsTest {
+
+ private final class DummyLabel extends Label {
+ private DummyLabel(String content) {
+ super(content);
+ }
+
+ @Override
+ public String getConnectorId() {
+ return "";
+ }
+ }
+
+ public static class TestGrid extends Grid<String> {
+
+ /**
+ * Used to execute data generation
+ */
+ public void runDataGeneration() {
+ super.getDataCommunicator().beforeClientResponse(true);
+ }
+ }
+
+ private TestGrid grid;
+ private List<String> data;
+
+ @Before
+ public void setUp() {
+ grid = new TestGrid();
+ // Setup Grid and generate some details
+ data = new ArrayList<>(Arrays.asList("Foo", "Bar"));
+ grid.setItems(data);
+ grid.setDetailsGenerator(s -> new DummyLabel(s));
+
+ data.forEach(s -> grid.setDetailsVisible(s, true));
+
+ grid.runDataGeneration();
+ }
+
+ @Test
+ public void testGridComponentIteratorContainsDetailsComponents() {
+ Iterator<Component> i = grid.iterator();
+
+ while (i.hasNext()) {
+ Component c = i.next();
+ if (c instanceof Label) {
+ String value = ((Label) c).getValue();
+ Assert.assertTrue(
+ "Unexpected label in component iterator with value "
+ + value,
+ data.remove(value));
+ } else {
+ Assert.fail(
+ "Iterator contained a component that is not a label.");
+ }
+ }
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGridComponentIteratorNotModifiable() {
+ Iterator<Component> iterator = grid.iterator();
+ iterator.next();
+ // This should fail
+ iterator.remove();
+ }
+
+ @Test
+ public void testGridComponentIteratorIsEmptyAfterHidingDetails() {
+ Assert.assertTrue("Component iterator should have components.",
+ grid.iterator().hasNext());
+ data.forEach(s -> grid.setDetailsVisible(s, false));
+ Assert.assertFalse("Component iterator should not have components.",
+ grid.iterator().hasNext());
+ }
+}
--- /dev/null
+package com.vaadin.tests.server.component.grid;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.function.Function;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.shared.ui.grid.HeightMode;
+import com.vaadin.ui.Grid;
+
+public class GridTest {
+
+ private Grid<String> grid;
+
+ @Before
+ public void setUp() {
+ grid = new Grid<>();
+ grid.addColumn("foo", String.class, Function.identity());
+ }
+
+ @Test
+ public void testGridHeightModeChange() {
+ assertEquals("Initial height mode was not CSS", HeightMode.CSS,
+ grid.getHeightMode());
+ grid.setHeightByRows(13.24);
+ assertEquals("Setting height by rows did not change height mode",
+ HeightMode.ROW, grid.getHeightMode());
+ grid.setHeight("100px");
+ assertEquals("Setting height did not change height mode.",
+ HeightMode.CSS, grid.getHeightMode());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testFrozenColumnCountTooBig() {
+ grid.setFrozenColumnCount(2);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testFrozenColumnCountTooSmall() {
+ grid.setFrozenColumnCount(-2);
+ }
+
+ @Test()
+ public void testSetFrozenColumnCount() {
+ for (int i = -1; i < 2; ++i) {
+ grid.setFrozenColumnCount(i);
+ assertEquals("Frozen column count not updated", i,
+ grid.getFrozenColumnCount());
+ }
+ }
+}
package com.vaadin.tests.components.grid.basics;
+import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+import com.vaadin.annotations.Widgetset;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.grid.HeightMode;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
+@Widgetset("com.vaadin.DefaultWidgetSet")
public class GridBasics extends AbstractTestUIWithLog {
private static class DetailedDetailsGenerator
private Component createMenu() {
MenuBar menu = new MenuBar();
MenuItem componentMenu = menu.addItem("Component", null);
+ createStateMenu(componentMenu.addItem("State", null));
+ createSizeMenu(componentMenu.addItem("Size", null));
createDetailsMenu(componentMenu.addItem("Details", null));
return menu;
}
+ private void createSizeMenu(MenuItem sizeMenu) {
+ MenuItem heightByRows = sizeMenu.addItem("Height by Rows", null);
+ DecimalFormat df = new DecimalFormat("0.00");
+ Stream.of(0.33, 0.67, 1.00, 1.33, 1.67, 2.00, 2.33, 2.67, 3.00, 3.33,
+ 3.67, 4.00, 4.33, 4.67)
+ .forEach(d -> addGridMethodMenu(heightByRows,
+ df.format(d) + " rows", d, grid::setHeightByRows));
+ sizeMenu.addItem("HeightMode Row", item -> {
+ grid.setHeightMode(
+ item.isChecked() ? HeightMode.ROW : HeightMode.CSS);
+ }).setCheckable(true);
+
+ MenuItem heightMenu = sizeMenu.addItem("Height", null);
+ Stream.of(50, 100, 200, 400).map(i -> i + "px").forEach(
+ i -> addGridMethodMenu(heightMenu, i, i, grid::setHeight));
+ }
+
+ private void createStateMenu(MenuItem stateMenu) {
+ MenuItem frozenColMenu = stateMenu.addItem("Frozen column count", null);
+ for (int i = -1; i < 3; ++i) {
+ addGridMethodMenu(frozenColMenu, "" + i, i,
+ grid::setFrozenColumnCount);
+ }
+ }
+
+ private <T> void addGridMethodMenu(MenuItem parent, String name, T value,
+ Consumer<T> method) {
+ parent.addItem(name, menuItem -> method.accept(value));
+ }
+
/* DetailsGenerator related things */
private void createDetailsMenu(MenuItem detailsMenu) {
--- /dev/null
+/*
+ * 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.basics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.TestBenchElement;
+
+public class GridBasicStructureTest extends GridBasicsTest {
+
+ @Test
+ public void testFreezingColumn() throws Exception {
+ // Freeze column 1
+ selectMenuPath("Component", "State", "Frozen column count", "1");
+
+ WebElement cell = getGridElement().getCell(0, 0);
+ assertTrue("First cell on a row should be frozen",
+ cell.getAttribute("class").contains("frozen"));
+
+ assertFalse("Second cell on a row should not be frozen",
+ getGridElement().getCell(0, 1).getAttribute("class")
+ .contains("frozen"));
+
+ int cellX = cell.getLocation().getX();
+ scrollGridHorizontallyTo(100);
+ assertEquals("First cell should not move when scrolling", cellX,
+ cell.getLocation().getX());
+ }
+
+ @Test
+ public void testHeightByRows() throws Exception {
+ int initialHeight = getGridElement().getSize().getHeight();
+
+ selectMenuPath("Component", "Size", "HeightMode Row");
+ selectMenuPath("Component", "Size", "Height by Rows", "2.00 rows");
+
+ TestBenchElement tableWrapper = getGridElement().getTableWrapper();
+ int rowHeight = getGridElement().getRow(0).getSize().getHeight();
+
+ assertTrue("Grid height was not 3 rows", Math
+ .abs(rowHeight * 3 - tableWrapper.getSize().getHeight()) < 2);
+
+ selectMenuPath("Component", "Size", "Height by Rows", "3.33 rows");
+
+ assertTrue("Grid height was not 4.33 rows", Math.abs(
+ rowHeight * 4.33 - tableWrapper.getSize().getHeight()) < 2);
+
+ selectMenuPath("Component", "Size", "HeightMode Row");
+ assertEquals("Grid should have returned to its original size",
+ initialHeight, getGridElement().getSize().getHeight());
+ }
+
+ @Test
+ public void testHeightModeChanges() throws Exception {
+ selectMenuPath("Component", "Size", "Height by Rows", "2.00 rows");
+
+ TestBenchElement tableWrapper = getGridElement().getTableWrapper();
+ int rowHeight = getGridElement().getRow(0).getSize().getHeight();
+
+ assertTrue("Grid height mode did not become ROW", Math
+ .abs(rowHeight * 3 - tableWrapper.getSize().getHeight()) < 2);
+
+ selectMenuPath("Component", "Size", "Height", "200px");
+
+ assertEquals("Grid height mode did not become CSS", 200,
+ getGridElement().getSize().getHeight());
+
+ }
+}