Skip to content

Commit

Permalink
Reintroduce frozen columns and height by rows to Grid
Browse files Browse the repository at this point in the history
Change-Id: I5fecfabd023b39dc252e47a6aa403a79034b0f3d
  • Loading branch information
Teemu Suo-Anttila authored and Artur- committed Sep 1, 2016
1 parent dcf64cd commit da8394e
Show file tree
Hide file tree
Showing 6 changed files with 333 additions and 1 deletion.
Expand Up @@ -38,6 +38,7 @@
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;

Expand Down Expand Up @@ -171,4 +172,9 @@ public HandlerRegistration addConnectorHierarchyChangeHandler(
return ensureHandlerManager()
.addHandler(ConnectorHierarchyChangeEvent.TYPE, handler);
}

@Override
public GridState getState() {
return (GridState) super.getState();
}
}
148 changes: 148 additions & 0 deletions server/src/main/java/com/vaadin/ui/Grid.java
Expand Up @@ -45,6 +45,7 @@
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;
Expand Down Expand Up @@ -628,6 +629,153 @@ public Iterator<Component> iterator() {
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);
Expand Down
@@ -1,4 +1,4 @@
package com.vaadin.tests.components.grid;
package com.vaadin.tests.server.component.grid;

import java.util.ArrayList;
import java.util.Arrays;
Expand Down
@@ -0,0 +1,53 @@
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());
}
}
}
@@ -1,12 +1,17 @@
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;
Expand All @@ -20,6 +25,7 @@
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;

@Widgetset("com.vaadin.DefaultWidgetSet")
public class GridBasics extends AbstractTestUIWithLog {

private static class DetailedDetailsGenerator
Expand Down Expand Up @@ -121,10 +127,42 @@ protected void setup(VaadinRequest request) {
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) {
Expand Down
@@ -0,0 +1,87 @@
/*
* 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());

}
}

0 comments on commit da8394e

Please sign in to comment.