diff options
6 files changed, 327 insertions, 2 deletions
diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 2388516a2d..671fd259d6 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -41,6 +41,7 @@ import com.vaadin.client.data.RpcDataSourceConnector.RpcDataSource; import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.AbstractHasComponentsConnector; import com.vaadin.client.ui.SimpleManagedLayout; +import com.vaadin.client.ui.grid.Grid.CellStyleGenerator; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector; import com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel; @@ -81,6 +82,35 @@ import com.vaadin.shared.ui.grid.SortDirection; public class GridConnector extends AbstractHasComponentsConnector implements SimpleManagedLayout { + private static final class CustomCellStyleGenerator implements + CellStyleGenerator<JSONObject> { + @Override + public String getStyle(Grid<JSONObject> grid, JSONObject row, + int rowIndex, GridColumn<?, JSONObject> column, int columnIndex) { + if (column == null) { + JSONValue styleValue = row.get(GridState.JSONKEY_ROWSTYLE); + if (styleValue != null) { + return styleValue.isString().stringValue(); + } else { + return null; + } + } else { + JSONValue cellstyles = row.get(GridState.JSONKEY_CELLSTYLES); + if (cellstyles == null) { + return null; + } + + CustomGridColumn c = (CustomGridColumn) column; + JSONValue styleValue = cellstyles.isObject().get(c.id); + if (styleValue != null) { + return styleValue.isString().stringValue(); + } else { + return null; + } + } + } + } + /** * Custom implementation of the custom grid column using a JSONObject to * represent the cell value and String as a column type. @@ -644,6 +674,15 @@ public class GridConnector extends AbstractHasComponentsConnector implements } } + @OnStateChange("hasCellStyleGenerator") + private void onCellStyleGeneratorChange() { + if (getState().hasCellStyleGenerator) { + getWidget().setCellStyleGenerator(new CustomCellStyleGenerator()); + } else { + getWidget().setCellStyleGenerator(null); + } + } + @OnStateChange("selectedKeys") private void updateSelectionFromState() { boolean changed = false; diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index ffef7e5b9e..d607879aa5 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -47,6 +47,7 @@ import com.vaadin.shared.data.DataRequestRpc; import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.Range; import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.CellStyleGenerator; import com.vaadin.ui.Grid.Column; import com.vaadin.ui.components.grid.Renderer; @@ -718,7 +719,6 @@ public class RpcDataProviderExtension extends AbstractExtension { Grid grid = getGrid(); - int i = 0; for (Object propertyId : propertyIds) { Column column = grid.getColumn(propertyId); @@ -733,9 +733,42 @@ public class RpcDataProviderExtension extends AbstractExtension { final JsonObject rowObject = Json.createObject(); rowObject.put(GridState.JSONKEY_DATA, rowData); rowObject.put(GridState.JSONKEY_ROWKEY, keyMapper.getKey(itemId)); + + CellStyleGenerator cellStyleGenerator = grid.getCellStyleGenerator(); + if (cellStyleGenerator != null) { + setGeneratedStyles(cellStyleGenerator, rowObject, propertyIds, + itemId); + } + return rowObject; } + private void setGeneratedStyles(CellStyleGenerator generator, + JsonObject rowObject, Collection<?> propertyIds, Object itemId) { + Grid grid = getGrid(); + + JsonObject cellStyles = null; + for (Object propertyId : propertyIds) { + String style = generator.getStyle(grid, itemId, propertyId); + if (style != null) { + if (cellStyles == null) { + cellStyles = Json.createObject(); + } + + String columnKey = columnKeys.key(propertyId); + cellStyles.put(columnKey, style); + } + } + if (cellStyles != null) { + rowObject.put(GridState.JSONKEY_CELLSTYLES, cellStyles); + } + + String rowStyle = generator.getStyle(grid, itemId, null); + if (rowStyle != null) { + rowObject.put(GridState.JSONKEY_ROWSTYLE, rowStyle); + } + } + @Override protected DataProviderState getState() { return (DataProviderState) super.getState(); @@ -813,6 +846,22 @@ public class RpcDataProviderExtension extends AbstractExtension { rpc.setRowData(index, rowArray.toJson()); } + /** + * Pushes a new version of all the rows in the active cache range. + */ + public void refreshCache() { + if (!clientInitialized) { + return; + } + + int firstRow = activeRowHandler.activeRange.getStart(); + int numberOfRows = activeRowHandler.activeRange.length(); + + List<?> itemIds = RpcDataProviderExtension.this.container.getItemIds( + firstRow, numberOfRows); + pushRows(firstRow, itemIds); + } + @Override public void setParent(ClientConnector parent) { super.setParent(parent); diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index 9732aa4612..992c666709 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -201,6 +201,37 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, } /** + * Callback interface for generating custom style names for data rows and + * cells. + * + * @see Grid#setCellStyleGenerator(CellStyleGenerator) + */ + public interface CellStyleGenerator extends Serializable { + + /** + * Called by Grid to generate a style name for a row or cell element. + * Row styles are generated when the column parameter is + * <code>null</code>, otherwise a cell style is generated. + * <p> + * The returned style name is prefixed so that the actual style for + * cells will be <tt>v-grid-cell-content-[style name]</tt>, and the row + * style will be <tt>v-grid-row-[style name]</tt>. + * + * @param grid + * the source grid + * @param itemId + * the itemId of the target row + * @param propertyId + * the propertyId of the target cell, <code>null</code> when + * getting row style + * @return the style name to add to this cell or row element, or + * <code>null</code> to not set any style + */ + public abstract String getStyle(Grid grid, Object itemId, + Object propertyId); + } + + /** * Abstract base class for Grid header and footer sections. * * @param <ROWTYPE> @@ -1941,6 +1972,8 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, private EditorRow editorRow; + private CellStyleGenerator cellStyleGenerator; + /** * <code>true</code> if Grid is using the internal IndexedContainer created * in Grid() constructor, or <code>false</code> if the user has set their @@ -3551,4 +3584,30 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, EditorRowClientRpc getEditorRowRpc() { return getRpcProxy(EditorRowClientRpc.class); } + + /** + * Sets the cell style generator that is used for generating styles for rows + * and cells. + * + * @param cellStyleGenerator + * the cell style generator to set, or <code>null</code> to + * remove a previously set generator + */ + public void setCellStyleGenerator(CellStyleGenerator cellStyleGenerator) { + this.cellStyleGenerator = cellStyleGenerator; + getState().hasCellStyleGenerator = (cellStyleGenerator != null); + + datasourceExtension.refreshCache(); + } + + /** + * Gets the cell style generator that is used for generating styles for rows + * and cells. + * + * @return the cell style generator, or <code>null</code> if no generator is + * set + */ + public CellStyleGenerator getCellStyleGenerator() { + return cellStyleGenerator; + } } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index 934ba25884..621b34a2b4 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -88,6 +88,20 @@ public class GridState extends AbstractComponentState { public static final String JSONKEY_ROWKEY = "k"; /** + * The key in which a row's generated style can be found + * + * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String) + */ + public static final String JSONKEY_ROWSTYLE = "rs"; + + /** + * The key in which a generated styles for a row's cells can be found + * + * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String) + */ + public static final String JSONKEY_CELLSTYLES = "cs"; + + /** * Columns in grid. */ public List<GridColumnState> columns = new ArrayList<GridColumnState>(); @@ -129,4 +143,7 @@ public class GridState extends AbstractComponentState { /** The enabled state of the editor row */ public boolean editorRowEnabled = false; + + /** Whether row data might contain generated styles */ + public boolean hasCellStyleGenerator; } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index c97d92249a..ccbb85da08 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -38,8 +38,9 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Grid; -import com.vaadin.ui.Grid.FooterCell; +import com.vaadin.ui.Grid.CellStyleGenerator; import com.vaadin.ui.Grid.Column; +import com.vaadin.ui.Grid.FooterCell; import com.vaadin.ui.Grid.HeaderCell; import com.vaadin.ui.Grid.HeaderRow; import com.vaadin.ui.Grid.SelectionMode; @@ -285,6 +286,58 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { } } }); + + LinkedHashMap<String, CellStyleGenerator> styleGenerators = new LinkedHashMap<String, CellStyleGenerator>(); + styleGenerators.put("None", null); + styleGenerators.put("Row only", new CellStyleGenerator() { + @Override + public String getStyle(Grid grid, Object itemId, Object propertyId) { + if (propertyId == null) { + return "row" + itemId; + } else { + return null; + } + } + }); + styleGenerators.put("Cell only", new CellStyleGenerator() { + @Override + public String getStyle(Grid grid, Object itemId, Object propertyId) { + if (propertyId == null) { + return null; + } else { + return propertyId.toString().replace(' ', '-'); + } + } + }); + styleGenerators.put("Combined", new CellStyleGenerator() { + @Override + public String getStyle(Grid grid, Object itemId, Object propertyId) { + int rowIndex = ((Integer) itemId).intValue(); + if (propertyId == null) { + if (rowIndex % 4 == 0) { + return null; + } else { + return "row" + itemId; + } + } else { + if (rowIndex % 4 == 1) { + return null; + } else if (rowIndex % 4 == 3 + && "Column 1".equals(propertyId)) { + return null; + } + return propertyId.toString().replace(' ', '_'); + } + } + }); + createSelectAction("Style generator", "State", styleGenerators, "None", + new Command<Grid, CellStyleGenerator>() { + @Override + public void execute(Grid grid, + CellStyleGenerator generator, Object data) { + grid.setCellStyleGenerator(generator); + } + }); } protected void createHeaderActions() { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridCellStyleGeneratorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridCellStyleGeneratorTest.java new file mode 100644 index 0000000000..24a575789e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridCellStyleGeneratorTest.java @@ -0,0 +1,108 @@ +/* + * Copyright 2000-2014 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.basicfeatures.server; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.tests.components.grid.GridElement.GridCellElement; +import com.vaadin.tests.components.grid.GridElement.GridRowElement; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; + +public class GridCellStyleGeneratorTest extends GridBasicFeaturesTest { + @Test + public void testStyleNameGeneratorScrolling() throws Exception { + openTestURL(); + + selectStyleNameGenerator("Combined"); + + GridRowElement row2 = getGridElement().getRow(2); + GridCellElement cell3_2 = getGridElement().getCell(3, 2); + + Assert.assertTrue(row2.getAttribute("class") + .contains("v-grid-row-row2")); + Assert.assertTrue(cell3_2.getAttribute("class").contains( + "v-grid-cell-content-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 + getGridElement().getRow(352); + + Assert.assertFalse(row2.getAttribute("class").contains( + "v-grid-row-row2")); + Assert.assertFalse(cell3_2.getAttribute("class").contains( + "v-grid-cell-content-Column_2")); + } + + @Test + public void testDisableStyleNameGenerator() throws Exception { + openTestURL(); + + selectStyleNameGenerator("Combined"); + + // Just verify that change was effective + GridRowElement row2 = getGridElement().getRow(2); + GridCellElement cell3_2 = getGridElement().getCell(3, 2); + + Assert.assertTrue(row2.getAttribute("class") + .contains("v-grid-row-row2")); + Assert.assertTrue(cell3_2.getAttribute("class").contains( + "v-grid-cell-content-Column_2")); + + // Disable the generator and check again + selectStyleNameGenerator("None"); + + Assert.assertFalse(row2.getAttribute("class").contains( + "v-grid-row-row2")); + Assert.assertFalse(cell3_2.getAttribute("class").contains( + "v-grid-cell-content-Column_2")); + } + + @Test + public void testChangeStyleNameGenerator() throws Exception { + openTestURL(); + + selectStyleNameGenerator("Combined"); + + // Just verify that change was effective + GridRowElement row2 = getGridElement().getRow(2); + GridCellElement cell3_2 = getGridElement().getCell(3, 2); + + Assert.assertTrue(row2.getAttribute("class") + .contains("v-grid-row-row2")); + Assert.assertTrue(cell3_2.getAttribute("class").contains( + "v-grid-cell-content-Column_2")); + + // Change the generator and check again + selectStyleNameGenerator("Cell only"); + + // Old styles removed? + Assert.assertFalse(row2.getAttribute("class").contains( + "v-grid-row-row2")); + Assert.assertFalse(cell3_2.getAttribute("class").contains( + "v-grid-cell-content-Column_2")); + + // New style present? + Assert.assertTrue(cell3_2.getAttribute("class").contains( + "v-grid-cell-content-Column-2")); + } + + private void selectStyleNameGenerator(String name) { + selectMenuPath("Component", "State", "Style generator", name); + } +} |