diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-09-06 15:07:37 +0300 |
---|---|---|
committer | Artur Signell <artur@vaadin.com> | 2016-09-08 11:33:14 +0000 |
commit | 74df0fadeb7d6c2a6e15b4716602d6ab7ffb54b1 (patch) | |
tree | 8d913860bc0e2fb9b14dafcf8cff149e641aea1a | |
parent | 8a4d90789ffd6a28ce29870bd176ace62f33288f (diff) | |
download | vaadin-framework-74df0fadeb7d6c2a6e15b4716602d6ab7ffb54b1.tar.gz vaadin-framework-74df0fadeb7d6c2a6e15b4716602d6ab7ffb54b1.zip |
Add StyleGenerators for Grid and Columns
Change-Id: I5eedce6ac24381d657357ff07ca1ccedd804158d
6 files changed, 337 insertions, 15 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java index ab0f6037f1..880de07d55 100644 --- a/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java +++ b/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java @@ -76,6 +76,29 @@ public class GridConnector // Default selection style is space key. spaceSelectHandler = new SpaceSelectHandler<JsonObject>(getWidget()); getWidget().addSortHandler(this::handleSortEvent); + getWidget().setRowStyleGenerator(rowRef -> { + JsonObject json = rowRef.getRow(); + return json.hasKey(GridState.JSONKEY_ROWSTYLE) + ? json.getString(GridState.JSONKEY_ROWSTYLE) : null; + }); + getWidget().setCellStyleGenerator(cellRef -> { + JsonObject row = cellRef.getRow(); + if (!row.hasKey(GridState.JSONKEY_CELLSTYLES)) { + return null; + } + + Column<?, JsonObject> column = cellRef.getColumn(); + if (columnToIdMap.containsKey(column)) { + String id = columnToIdMap.get(column); + JsonObject cellStyles = row + .getObject(GridState.JSONKEY_CELLSTYLES); + if (cellStyles.hasKey(id)) { + return cellStyles.getString(id); + } + } + + return null; + }); layout(); } diff --git a/server/src/main/java/com/vaadin/server/data/DataCommunicator.java b/server/src/main/java/com/vaadin/server/data/DataCommunicator.java index e8c96fddab..b0ade744de 100644 --- a/server/src/main/java/com/vaadin/server/data/DataCommunicator.java +++ b/server/src/main/java/com/vaadin/server/data/DataCommunicator.java @@ -357,7 +357,7 @@ public class DataCommunicator<T> extends AbstractExtension { /** * Informs the DataProvider that the collection has changed. */ - protected void reset() { + public void reset() { if (reset) { return; } diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java index 94a3dd0ce9..96d7376816 100644 --- a/server/src/main/java/com/vaadin/ui/Grid.java +++ b/server/src/main/java/com/vaadin/ui/Grid.java @@ -32,9 +32,7 @@ import java.util.function.Function; import java.util.stream.Stream; import com.vaadin.data.selection.SingleSelection; -import com.vaadin.server.AbstractExtension; import com.vaadin.server.KeyMapper; -import com.vaadin.server.data.DataGenerator; import com.vaadin.server.data.SortOrder; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.data.DataCommunicatorConstants; @@ -65,6 +63,17 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>> implements HasComponents { /** + * A callback interface for generating style names for an item. + * + * @param <T> + * the grid bean type + */ + @FunctionalInterface + public interface StyleGenerator<T> + extends Function<T, String>, Serializable { + } + + /** * A callback interface for generating details for a particular row in Grid. * * @param <T> @@ -304,13 +313,13 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>> * @param <V> * the column value type */ - public static class Column<T, V> extends AbstractExtension - implements DataGenerator<T> { + public static class Column<T, V> extends AbstractGridExtension<T> { private final Function<T, ? extends V> valueProvider; private Function<SortDirection, Stream<SortOrder<String>>> sortOrderProvider; private Comparator<T> comparator; + private StyleGenerator<T> styleGenerator; /** * Constructs a new Column configuration with given header caption, @@ -401,22 +410,41 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>> @SuppressWarnings("unchecked") Renderer<V> renderer = (Renderer<V>) state.renderer; - if (!jsonObject.hasKey(DataCommunicatorConstants.DATA)) { - jsonObject.put(DataCommunicatorConstants.DATA, - Json.createObject()); - } - JsonObject obj = jsonObject - .getObject(DataCommunicatorConstants.DATA); + JsonObject obj = getDataObject(jsonObject, + DataCommunicatorConstants.DATA); V providerValue = valueProvider.apply(data); JsonValue rendererValue = renderer.encode(providerValue); obj.put(communicationId, rendererValue); + + if (styleGenerator != null) { + String style = styleGenerator.apply(data); + if (style != null && !style.isEmpty()) { + JsonObject styleObj = getDataObject(jsonObject, + GridState.JSONKEY_CELLSTYLES); + styleObj.put(getState(false).id, style); + } + } } - @Override - public void destroyData(T data) { + /** + * Gets a data object with the given key from the given JsonObject. If + * there is no object with the key, this method creates a new + * JsonObject. + * + * @param jsonObject + * the json object + * @param key + * the key where the desired data object is stored + * @return data object for the given key + */ + private JsonObject getDataObject(JsonObject jsonObject, String key) { + if (!jsonObject.hasKey(key)) { + jsonObject.put(key, Json.createObject()); + } + return jsonObject.getObject(key); } @Override @@ -572,6 +600,33 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>> public Stream<SortOrder<String>> getSortOrder(SortDirection direction) { return sortOrderProvider.apply(direction); } + + /** + * Sets the style generator that is used for generating styles for cells + * in this column. + * + * @param cellStyleGenerator + * the cell style generator to set, or <code>null</code> to + * remove a previously set generator + * @return this column + */ + public Column<T, V> setStyleGenerator( + StyleGenerator<T> cellStyleGenerator) { + this.styleGenerator = cellStyleGenerator; + getParent().getDataCommunicator().reset(); + return this; + } + + /** + * Gets the style generator that is used for generating styles for + * cells. + * + * @return the cell style generator, or <code>null</code> if no + * generator is set + */ + public StyleGenerator<T> getStyleGenerator() { + return styleGenerator; + } } private KeyMapper<Column<T, ?>> columnKeys = new KeyMapper<>(); @@ -579,6 +634,7 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>> private List<SortOrder<Column<T, ?>>> sortOrder = new ArrayList<>(); private DetailsManager<T> detailsManager; private Set<Component> extensionComponents = new HashSet<>(); + private StyleGenerator<T> styleGenerator; /** * Constructor for the {@link Grid} component. @@ -589,6 +645,14 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>> detailsManager = new DetailsManager<>(); addExtension(detailsManager); addDataGenerator(detailsManager); + addDataGenerator((item, json) -> { + if (styleGenerator != null) { + String styleName = styleGenerator.apply(item); + if (styleName != null && !styleName.isEmpty()) { + json.put(GridState.JSONKEY_ROWSTYLE, styleName); + } + } + }); } /** @@ -836,6 +900,28 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>> return getState(false).heightMode; } + /** + * Sets the style generator that is used for generating styles for rows. + * + * @param styleGenerator + * the row style generator to set, or <code>null</code> to remove + * a previously set generator + */ + public void setStyleGenerator(StyleGenerator<T> styleGenerator) { + this.styleGenerator = styleGenerator; + getDataCommunicator().reset(); + } + + /** + * Gets the style generator that is used for generating styles for rows. + * + * @return the row style generator, or <code>null</code> if no generator is + * set + */ + public StyleGenerator<T> getStyleGenerator() { + return styleGenerator; + } + @Override protected GridState getState() { return getState(true); diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java index a47d8b3e9e..5c9f03336e 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java @@ -18,6 +18,7 @@ import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; import com.vaadin.ui.Grid; import com.vaadin.ui.Grid.DetailsGenerator; +import com.vaadin.ui.Grid.StyleGenerator; import com.vaadin.ui.Label; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; @@ -32,6 +33,17 @@ import com.vaadin.ui.renderers.ProgressBarRenderer; @Widgetset("com.vaadin.DefaultWidgetSet") public class GridBasics extends AbstractTestUIWithLog { + public static final String ROW_STYLE_GENERATOR_ROW_NUMBERS_FOR_3_OF_4 = "Row numbers for 3/4"; + public static final String ROW_STYLE_GENERATOR_NONE = "None"; + public static final String ROW_STYLE_GENERATOR_ROW_NUMBERS = "Row numbers"; + public static final String ROW_STYLE_GENERATOR_EMPTY = "Empty string"; + public static final String ROW_STYLE_GENERATOR_NULL = "Null"; + public static final String CELL_STYLE_GENERATOR_NONE = "None"; + public static final String CELL_STYLE_GENERATOR_PROPERTY_TO_STRING = "Property to string"; + public static final String CELL_STYLE_GENERATOR_SPECIAL = "Special for 1/4 Column 1"; + public static final String CELL_STYLE_GENERATOR_EMPTY = "Empty string"; + public static final String CELL_STYLE_GENERATOR_NULL = "Null"; + private static class DetailedDetailsGenerator implements DetailsGenerator<DataObject> { @@ -120,6 +132,8 @@ public class GridBasics extends AbstractTestUIWithLog { dataObj -> "(" + dataObj.getRowNumber() + ", 0)"); grid.addColumn("Column 1", dataObj -> "(" + dataObj.getRowNumber() + ", 1)"); + grid.addColumn("Column 2", + dataObj -> "(" + dataObj.getRowNumber() + ", 2)"); grid.addColumn("Row Number", DataObject::getRowNumber, new NumberRenderer()); @@ -172,6 +186,50 @@ public class GridBasics extends AbstractTestUIWithLog { addGridMethodMenu(frozenColMenu, "" + i, i, grid::setFrozenColumnCount); } + createRowStyleMenu(stateMenu.addItem("Row style generator", null)); + createCellStyleMenu(stateMenu.addItem("Cell style generator", null)); + } + + private void createRowStyleMenu(MenuItem rowStyleMenu) { + addGridMethodMenu(rowStyleMenu, ROW_STYLE_GENERATOR_NONE, null, + grid::setStyleGenerator); + addGridMethodMenu(rowStyleMenu, ROW_STYLE_GENERATOR_ROW_NUMBERS, + t -> "row" + t.getRowNumber(), grid::setStyleGenerator); + addGridMethodMenu(rowStyleMenu, + ROW_STYLE_GENERATOR_ROW_NUMBERS_FOR_3_OF_4, + t -> t.getRowNumber() % 4 != 0 ? "row" + t.getRowNumber() + : null, + grid::setStyleGenerator); + addGridMethodMenu(rowStyleMenu, ROW_STYLE_GENERATOR_EMPTY, t -> "", + grid::setStyleGenerator); + addGridMethodMenu(rowStyleMenu, ROW_STYLE_GENERATOR_NULL, t -> null, + grid::setStyleGenerator); + } + + private void createCellStyleMenu(MenuItem cellStyleMenu) { + addGridMethodMenu(cellStyleMenu, CELL_STYLE_GENERATOR_NONE, + (StyleGenerator<DataObject>) null, + sg -> grid.getColumns().forEach(c -> c.setStyleGenerator(sg))); + addGridMethodMenu(cellStyleMenu, CELL_STYLE_GENERATOR_EMPTY, + (StyleGenerator<DataObject>) t -> "", + sg -> grid.getColumns().forEach(c -> c.setStyleGenerator(sg))); + addGridMethodMenu(cellStyleMenu, + CELL_STYLE_GENERATOR_PROPERTY_TO_STRING, null, + sg -> grid.getColumns().forEach(c -> c.setStyleGenerator( + t -> c.getCaption().replaceAll(" ", "-")))); + addGridMethodMenu(cellStyleMenu, CELL_STYLE_GENERATOR_SPECIAL, null, + sg -> grid.getColumns().forEach(c -> c.setStyleGenerator(t -> { + if (t.getRowNumber() % 4 == 1) { + return null; + } else if (t.getRowNumber() % 4 == 3 + && c.getCaption().equals("Column 1")) { + return null; + } + return c.getCaption().replaceAll(" ", "_"); + }))); + addGridMethodMenu(cellStyleMenu, CELL_STYLE_GENERATOR_NULL, + (StyleGenerator<DataObject>) t -> null, + sg -> grid.getColumns().forEach(c -> c.setStyleGenerator(sg))); } private <T> void addGridMethodMenu(MenuItem parent, String name, T value, diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicStyleGeneratorTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicStyleGeneratorTest.java new file mode 100644 index 0000000000..b9b93fa884 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicStyleGeneratorTest.java @@ -0,0 +1,155 @@ +/* + * 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.assertFalse; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import com.vaadin.testbench.elements.GridElement.GridCellElement; +import com.vaadin.testbench.elements.GridElement.GridRowElement; +import com.vaadin.testbench.elements.NotificationElement; + +public class GridBasicStyleGeneratorTest extends GridBasicsTest { + @Test + public void testStyleNameGeneratorScrolling() throws Exception { + openTestURL(); + + selectRowStyleNameGenerator( + GridBasics.ROW_STYLE_GENERATOR_ROW_NUMBERS_FOR_3_OF_4); + selectCellStyleNameGenerator(GridBasics.CELL_STYLE_GENERATOR_SPECIAL); + + GridRowElement row = getGridElement().getRow(2); + GridCellElement cell = getGridElement().getCell(3, 2); + + Assert.assertTrue(hasCssClass(row, "row2")); + Assert.assertTrue(hasCssClass(cell, "Column_2")); + + // Scroll down and verify that the old elements don't have the + // stylename any more + + // Carefully chosen offset to hit an index % 4 without cell style + row = getGridElement().getRow(352); + cell = getGridElement().getCell(353, 2); + + Assert.assertFalse(hasCssClass(row, "row352")); + Assert.assertFalse(hasCssClass(cell, "Column_2")); + } + + @Test + public void testDisableStyleNameGenerator() throws Exception { + openTestURL(); + + selectRowStyleNameGenerator( + GridBasics.ROW_STYLE_GENERATOR_ROW_NUMBERS_FOR_3_OF_4); + selectCellStyleNameGenerator(GridBasics.CELL_STYLE_GENERATOR_SPECIAL); + + // Just verify that change was effective + GridRowElement row = getGridElement().getRow(2); + GridCellElement cell = getGridElement().getCell(3, 2); + + Assert.assertTrue(hasCssClass(row, "row2")); + Assert.assertTrue(hasCssClass(cell, "Column_2")); + + // Disable the generator and check again + selectRowStyleNameGenerator(GridBasics.ROW_STYLE_GENERATOR_NONE); + selectCellStyleNameGenerator(GridBasics.CELL_STYLE_GENERATOR_NONE); + + row = getGridElement().getRow(2); + cell = getGridElement().getCell(3, 2); + + Assert.assertFalse(hasCssClass(row, "row2")); + Assert.assertFalse(hasCssClass(cell, "Column_2")); + } + + @Test + public void testChangeStyleNameGenerator() throws Exception { + openTestURL(); + + selectRowStyleNameGenerator( + GridBasics.ROW_STYLE_GENERATOR_ROW_NUMBERS_FOR_3_OF_4); + selectCellStyleNameGenerator(GridBasics.CELL_STYLE_GENERATOR_SPECIAL); + + // Just verify that change was effective + GridRowElement row = getGridElement().getRow(2); + GridCellElement cell = getGridElement().getCell(3, 2); + + Assert.assertTrue(hasCssClass(row, "row2")); + Assert.assertTrue(hasCssClass(cell, "Column_2")); + + // Change the generator and check again + selectRowStyleNameGenerator(GridBasics.ROW_STYLE_GENERATOR_NONE); + selectCellStyleNameGenerator( + GridBasics.CELL_STYLE_GENERATOR_PROPERTY_TO_STRING); + + row = getGridElement().getRow(2); + cell = getGridElement().getCell(3, 2); + + // Old styles removed? + Assert.assertFalse(hasCssClass(row, "row2")); + Assert.assertFalse(hasCssClass(cell, "Column_2")); + + // New style present? + Assert.assertTrue(hasCssClass(cell, "Column-2")); + } + + @Test + @Ignore + public void testCellStyleGeneratorWithSelectionColumn() { + setDebug(true); + openTestURL(); + selectMenuPath("Component", "State", "Selection mode", "multi"); + + selectCellStyleNameGenerator(GridBasics.CELL_STYLE_GENERATOR_SPECIAL); + + assertFalse("Error notification was present", + isElementPresent(NotificationElement.class)); + } + + private void selectRowStyleNameGenerator(String name) { + selectMenuPath("Component", "State", "Row style generator", name); + } + + private void selectCellStyleNameGenerator(String name) { + selectMenuPath("Component", "State", "Cell style generator", name); + } + + @Test + public void testEmptyStringStyleGenerator() { + setDebug(true); + openTestURL(); + + selectCellStyleNameGenerator(GridBasics.CELL_STYLE_GENERATOR_EMPTY); + selectRowStyleNameGenerator(GridBasics.ROW_STYLE_GENERATOR_EMPTY); + + assertFalse("Error notification was present", + isElementPresent(NotificationElement.class)); + } + + @Test + public void testNullStringStyleGenerator() { + setDebug(true); + openTestURL(); + + selectCellStyleNameGenerator(GridBasics.CELL_STYLE_GENERATOR_NULL); + selectRowStyleNameGenerator(GridBasics.ROW_STYLE_GENERATOR_NULL); + + assertFalse("Error notification was present", + isElementPresent(NotificationElement.class)); + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridContentTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridContentTest.java index 88f2eb0b20..ba7187a5ec 100644 --- a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridContentTest.java +++ b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridContentTest.java @@ -10,8 +10,8 @@ public class GridContentTest extends GridBasicsTest { DataObject first = getTestData().findFirst().orElse(null); Assert.assertEquals("Text content should match row number", first.getRowNumber().toString(), - getGridElement().getCell(0, 4).getText()); + getGridElement().getCell(0, 5).getText()); Assert.assertEquals("HTML content did not match", first.getHtmlString(), - getGridElement().getCell(0, 4).getAttribute("innerHTML")); + getGridElement().getCell(0, 5).getAttribute("innerHTML")); } } |