Change-Id: Id12f1135673d93fddd0a59d26b1c546a0ef0ee1dtags/7.4.0.beta1
@@ -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; |
@@ -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); |
@@ -200,6 +200,37 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, | |||
protected abstract SelectionModel createModel(); | |||
} | |||
/** | |||
* 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. | |||
* | |||
@@ -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; | |||
} | |||
} |
@@ -87,6 +87,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. | |||
*/ | |||
@@ -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; | |||
} |
@@ -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() { |
@@ -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); | |||
} | |||
} |