// 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();
}
/**
* Informs the DataProvider that the collection has changed.
*/
- protected void reset() {
+ public void reset() {
if (reset) {
return;
}
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;
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 <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,
@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
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<>();
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.
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);
+ }
+ }
+ });
}
/**
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);
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;
@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> {
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());
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,
--- /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.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));
+ }
+}
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"));
}
}