Skip to content

Commit

Permalink
Use identifiers for Grid Columns
Browse files Browse the repository at this point in the history
Change-Id: Id229e533fc4ff58bdd2ce3862481f72210ed9e89
  • Loading branch information
Teemu Suo-Anttila authored and Vaadin Code Review committed Oct 17, 2016
1 parent ace0e32 commit b49b8c2
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 63 deletions.
Expand Up @@ -36,24 +36,36 @@
@Connect(com.vaadin.ui.Grid.Column.class)
public class ColumnConnector extends AbstractExtensionConnector {

private Column<Object, JsonObject> column;
static abstract class CustomColumn extends Column<Object, JsonObject> {

private final String connectorId;

CustomColumn(String connectorId) {
this.connectorId = connectorId;
}

public String getConnectorId() {
return connectorId;
}
}

private CustomColumn column;

/* This parent is needed because it's no longer available in onUnregister */
private GridConnector parent;

@Override
protected void extend(ServerConnector target) {
parent = getParent();
String columnId = getState().id;
column = new Column<Object, JsonObject>() {
column = new CustomColumn(getConnectorId()) {

@Override
public Object getValue(JsonObject row) {
final JsonObject rowData = row
.getObject(DataCommunicatorConstants.DATA);

if (rowData.hasKey(columnId)) {
final JsonValue columnValue = rowData.get(columnId);
if (rowData.hasKey(getConnectorId())) {
final JsonValue columnValue = rowData.get(getConnectorId());

return getRendererConnector().decode(columnValue);
}
Expand All @@ -62,7 +74,7 @@ public Object getValue(JsonObject row) {
}
};
column.setRenderer(getRendererConnector().getRenderer());
getParent().addColumn(column, columnId);
getParent().addColumn(column, getState().id);
}

@SuppressWarnings("unchecked")
Expand Down
Expand Up @@ -38,6 +38,7 @@
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.connectors.AbstractListingConnector;
import com.vaadin.client.connectors.grid.ColumnConnector.CustomColumn;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.ui.SimpleManagedLayout;
import com.vaadin.client.widget.grid.CellReference;
Expand Down Expand Up @@ -107,8 +108,8 @@ private void fireItemClick(CellReference<?> cell,
}

/* Map to keep track of all added columns */
private Map<Column<?, JsonObject>, String> columnToIdMap = new HashMap<>();
private Map<String, Column<?, JsonObject>> idToColumn = new HashMap<>();
private Map<CustomColumn, String> columnToIdMap = new HashMap<>();
private Map<String, CustomColumn> idToColumn = new HashMap<>();

/* Child component list for HasComponentsConnector */
private List<ComponentConnector> childComponents;
Expand All @@ -134,7 +135,7 @@ public String getColumnId(Column<?, ?> column) {
* the id of the column to get
* @return the column with the given id
*/
public Column<?, JsonObject> getColumn(String columnId) {
public CustomColumn getColumn(String columnId) {
return idToColumn.get(columnId);
}

Expand Down Expand Up @@ -164,8 +165,8 @@ protected void init() {
}

Column<?, JsonObject> column = cellRef.getColumn();
if (columnToIdMap.containsKey(column)) {
String id = columnToIdMap.get(column);
if (column instanceof CustomColumn) {
String id = ((CustomColumn) column).getConnectorId();
JsonObject cellStyles = row
.getObject(GridState.JSONKEY_CELLSTYLES);
if (cellStyles.hasKey(id)) {
Expand Down Expand Up @@ -284,7 +285,7 @@ public void setSelectionModel(SelectionModel<JsonObject> selectionModel) {
* @param id
* communication id
*/
public void addColumn(Column<?, JsonObject> column, String id) {
public void addColumn(CustomColumn column, String id) {
assert !columnToIdMap.containsKey(column) && !columnToIdMap
.containsValue(id) : "Column with given id already exists.";
getWidget().addColumn(column);
Expand All @@ -299,7 +300,7 @@ public void addColumn(Column<?, JsonObject> column, String id) {
* @param column
* column to remove
*/
public void removeColumn(Column<?, JsonObject> column) {
public void removeColumn(CustomColumn column) {
assert columnToIdMap
.containsKey(column) : "Given Column does not exist.";
getWidget().removeColumn(column);
Expand Down Expand Up @@ -407,11 +408,11 @@ public TooltipInfo getTooltipInfo(Element element) {
|| row.hasKey(GridState.JSONKEY_CELLDESCRIPTION))) {

Column<?, JsonObject> column = cell.getColumn();
if (columnToIdMap.containsKey(column)) {
if (column instanceof CustomColumn) {
JsonObject cellDescriptions = row
.getObject(GridState.JSONKEY_CELLDESCRIPTION);

String id = columnToIdMap.get(column);
String id = ((CustomColumn) column).getConnectorId();
if (cellDescriptions != null
&& cellDescriptions.hasKey(id)) {
return new TooltipInfo(cellDescriptions.getString(id));
Expand Down
98 changes: 76 additions & 22 deletions server/src/main/java/com/vaadin/ui/Grid.java
Expand Up @@ -41,7 +41,6 @@
import com.vaadin.event.EventListener;
import com.vaadin.server.EncodeResult;
import com.vaadin.server.JsonCodec;
import com.vaadin.server.KeyMapper;
import com.vaadin.server.data.SortOrder;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Registration;
Expand All @@ -54,6 +53,7 @@
import com.vaadin.shared.ui.grid.GridState;
import com.vaadin.shared.ui.grid.HeightMode;
import com.vaadin.shared.ui.grid.SectionState;
import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.components.grid.Header;
import com.vaadin.ui.components.grid.Header.Row;
import com.vaadin.ui.renderers.AbstractRenderer;
Expand Down Expand Up @@ -841,7 +841,7 @@ private static int compareNumbers(Number a, Number b) {
public void generateData(T data, JsonObject jsonObject) {
ColumnState state = getState(false);

String communicationId = state.id;
String communicationId = getConnectorId();

assert communicationId != null : "No communication ID set for column "
+ state.caption;
Expand Down Expand Up @@ -1575,8 +1575,9 @@ protected SectionState getState(boolean markAsDirty) {
}
};

private KeyMapper<Column<T, ?>> columnKeys = new KeyMapper<>();
private Set<Column<T, ?>> columnSet = new LinkedHashSet<>();
private Map<String, Column<T, ?>> columnKeys = new HashMap<>();

private List<SortOrder<Column<T, ?>>> sortOrder = new ArrayList<>();
private DetailsManager<T> detailsManager;
private Set<Component> extensionComponents = new HashSet<>();
Expand All @@ -1585,6 +1586,8 @@ protected SectionState getState(boolean markAsDirty) {

private Header header = new HeaderImpl();

private int counter = 0;

/**
* Constructor for the {@link Grid} component.
*/
Expand Down Expand Up @@ -1619,11 +1622,11 @@ public <V> void fireColumnVisibilityChangeEvent(Column<T, V> column,
}

/**
* Adds a new column to this {@link Grid} with given header caption, typed
* Adds a new column to this {@link Grid} with given identifier, typed
* renderer and value provider.
*
* @param caption
* the header caption
* @param identifier
* the identifier in camel case for the new column
* @param valueProvider
* the value provider
* @param renderer
Expand All @@ -1635,48 +1638,86 @@ public <V> void fireColumnVisibilityChangeEvent(Column<T, V> column,
*
* @see {@link AbstractRenderer}
*/
public <V> Column<T, V> addColumn(String caption,
public <V> Column<T, V> addColumn(String identifier,
Function<T, ? extends V> valueProvider,
AbstractRenderer<? super T, V> renderer) {
final Column<T, V> column = new Column<>(caption, valueProvider,
assert !columnKeys.containsKey(identifier) : "Duplicate identifier: "
+ identifier;

final Column<T, V> column = new Column<>(
SharedUtil.camelCaseToHumanFriendly(identifier), valueProvider,
renderer);
addColumn(column);
addColumn(identifier, column);
return column;
}

/**
* Adds a new text column to this {@link Grid} with given header caption
* Adds a new text column to this {@link Grid} with given identifier and
* string value provider. The column will use a {@link TextRenderer}.
*
* @param caption
* @param identifier
* the header caption
* @param valueProvider
* the value provider
*
* @return the new column
*/
public Column<T, String> addColumn(String caption,
public Column<T, String> addColumn(String identifier,
Function<T, String> valueProvider) {
return addColumn(caption, valueProvider, new TextRenderer());
return addColumn(identifier, valueProvider, new TextRenderer());
}

/**
* Adds a new text column to this {@link Grid} with string value provider.
* The column will use a {@link TextRenderer}. Identifier for the column is
* generated automatically.
*
* @param valueProvider
* the value provider
*
* @return the new column
*/
public Column<T, String> addColumn(Function<T, String> valueProvider) {
return addColumn(getGeneratedIdentifier(), valueProvider,
new TextRenderer());
}

/**
* Adds a new column to this {@link Grid} with typed renderer and value
* provider. Identifier for the column is generated automatically.
*
* @param valueProvider
* the value provider
* @param renderer
* the column value class
* @param <V>
* the column value type
*
* @return the new column
*
* @see {@link AbstractRenderer}
*/
public <V> Column<T, V> addColumn(Function<T, ? extends V> valueProvider,
AbstractRenderer<? super T, V> renderer) {
return addColumn(getGeneratedIdentifier(), valueProvider, renderer);
}

private void addColumn(Column<T, ?> column) {
private void addColumn(String identifier, Column<T, ?> column) {
if (getColumns().contains(column)) {
return;
}

final String columnId = columnKeys.key(column);

column.extend(this);
column.setId(columnId);
columnSet.add(column);
columnKeys.put(identifier, column);
column.setId(identifier);
addDataGenerator(column);

getState().columnOrder.add(columnId);
getHeader().addColumn(columnId);
getState().columnOrder.add(identifier);
getHeader().addColumn(identifier);

if (getDefaultHeaderRow() != null) {
getDefaultHeaderRow().getCell(columnId)
getDefaultHeaderRow().getCell(identifier)
.setText(column.getCaption());
}
}
Expand All @@ -1689,7 +1730,7 @@ private void addColumn(Column<T, ?> column) {
*/
public void removeColumn(Column<T, ?> column) {
if (columnSet.remove(column)) {
columnKeys.remove(column);
columnKeys.remove(column.getId());
removeDataGenerator(column);
getHeader().removeColumn(column.getId());
column.remove();
Expand Down Expand Up @@ -2205,11 +2246,24 @@ public void setColumns(Column<T, ?>... columns) {
removeColumns.stream().forEach(this::removeColumn);

addColumns.removeAll(currentColumns);
addColumns.stream().forEach(this::addColumn);
addColumns.stream().forEach(c -> addColumn(getIdentifier(c), c));

setColumnOrder(columns);
}

private String getIdentifier(Column<T, ?> column) {
return columnKeys.entrySet().stream()
.filter(entry -> entry.getValue().equals(column))
.map(entry -> entry.getKey()).findFirst()
.orElse(getGeneratedIdentifier());
}

private String getGeneratedIdentifier() {
String columnId = "generatedColumn" + counter;
counter = counter + 1;
return columnId;
}

/**
* Sets a new column order for the grid. All columns which are not ordered
* here will remain in the order they were before as the last columns of
Expand Down
Expand Up @@ -9,6 +9,7 @@

import com.vaadin.shared.ui.grid.HeightMode;
import com.vaadin.ui.Grid;
import com.vaadin.ui.renderers.NumberRenderer;

public class GridTest {

Expand All @@ -18,6 +19,8 @@ public class GridTest {
public void setUp() {
grid = new Grid<>();
grid.addColumn("foo", Function.identity());
grid.addColumn(String::length, new NumberRenderer());
grid.addColumn("randomColumnId", Function.identity());
}

@Test
Expand All @@ -34,7 +37,7 @@ public void testGridHeightModeChange() {

@Test(expected = IllegalArgumentException.class)
public void testFrozenColumnCountTooBig() {
grid.setFrozenColumnCount(2);
grid.setFrozenColumnCount(5);
}

@Test(expected = IllegalArgumentException.class)
Expand All @@ -50,4 +53,25 @@ public void testSetFrozenColumnCount() {
grid.getFrozenColumnCount());
}
}

@Test
public void testGridColumnIdentifier() {
grid.getColumn("foo").setCaption("Bar");
assertEquals("Column header not updated correctly", "Bar",
grid.getHeaderRow(0).getCell("foo").getText());
}

@Test
public void testGridColumnGeneratedIdentifier() {
assertEquals("Unexpected caption on a generated Column",
"Generated Column0",
grid.getColumn("generatedColumn0").getCaption());
}

@Test
public void testGridColumnCaptionFromIdentifier() {
assertEquals("Unexpected caption on a generated Column",
"Random Column Id",
grid.getColumn("randomColumnId").getCaption());
}
}

0 comments on commit b49b8c2

Please sign in to comment.