Change-Id: I7a3fa34749322451ab5cef4465d4d7c76029c097tags/8.0.0.alpha3
@@ -34,6 +34,7 @@ import com.vaadin.client.HasComponentsConnector; | |||
import com.vaadin.client.MouseEventDetailsBuilder; | |||
import com.vaadin.client.TooltipInfo; | |||
import com.vaadin.client.WidgetUtil; | |||
import com.vaadin.client.annotations.OnStateChange; | |||
import com.vaadin.client.connectors.AbstractListingConnector; | |||
import com.vaadin.client.data.DataSource; | |||
import com.vaadin.client.ui.SimpleManagedLayout; | |||
@@ -49,6 +50,7 @@ import com.vaadin.client.widget.grid.sort.SortEvent; | |||
import com.vaadin.client.widget.grid.sort.SortOrder; | |||
import com.vaadin.client.widgets.Grid; | |||
import com.vaadin.client.widgets.Grid.Column; | |||
import com.vaadin.client.widgets.Grid.HeaderRow; | |||
import com.vaadin.shared.MouseEventDetails; | |||
import com.vaadin.shared.data.DataCommunicatorConstants; | |||
import com.vaadin.shared.data.selection.SelectionModel; | |||
@@ -59,6 +61,8 @@ import com.vaadin.shared.ui.grid.GridConstants; | |||
import com.vaadin.shared.ui.grid.GridConstants.Section; | |||
import com.vaadin.shared.ui.grid.GridServerRpc; | |||
import com.vaadin.shared.ui.grid.GridState; | |||
import com.vaadin.shared.ui.grid.SectionState; | |||
import com.vaadin.shared.ui.grid.SectionState.RowState; | |||
import elemental.json.JsonObject; | |||
@@ -102,6 +106,8 @@ public class GridConnector | |||
/* Map to keep track of all added columns */ | |||
private Map<Column<?, JsonObject>, String> columnToIdMap = new HashMap<>(); | |||
private Map<String, Column<?, JsonObject>> idToColumn = new HashMap<>(); | |||
/* Child component list for HasComponentsConnector */ | |||
private List<ComponentConnector> childComponents; | |||
private SpaceSelectHandler<JsonObject> spaceSelectHandler; | |||
@@ -109,16 +115,27 @@ public class GridConnector | |||
private ItemClickHandler itemClickHandler = new ItemClickHandler(); | |||
/** | |||
* Gets the string identifier of a {@link Column} in this grid. | |||
* Gets the string identifier of the given column in this grid. | |||
* | |||
* @param column | |||
* the column for which the identifier is to be retrieved for | |||
* @return the string identifying the given column in this grid | |||
* the column whose id to get | |||
* @return the string id of the column | |||
*/ | |||
public String getColumnId(Grid.Column<?, ?> column) { | |||
public String getColumnId(Column<?, ?> column) { | |||
return columnToIdMap.get(column); | |||
} | |||
/** | |||
* Gets the column corresponding to the given string identifier. | |||
* | |||
* @param columnId | |||
* the id of the column to get | |||
* @return the column with the given id | |||
*/ | |||
public Column<?, ?> getColumn(String columnId) { | |||
return idToColumn.get(columnId); | |||
} | |||
@Override | |||
@SuppressWarnings("unchecked") | |||
public Grid<JsonObject> getWidget() { | |||
@@ -202,6 +219,28 @@ public class GridConnector | |||
layout(); | |||
} | |||
@OnStateChange("header") | |||
void updateHeader() { | |||
final SectionState state = getState().header; | |||
final Grid<JsonObject> grid = getWidget(); | |||
while (grid.getHeaderRowCount() > 0) { | |||
grid.removeHeaderRow(0); | |||
} | |||
for (RowState rowState : state.rows) { | |||
HeaderRow row = grid.appendHeaderRow(); | |||
rowState.cells.forEach((columnId, cellState) -> { | |||
row.getCell(getColumn(columnId)).setText(cellState.text); | |||
}); | |||
} | |||
if (grid.getHeaderRowCount() > 0) { | |||
// TODO Default header handling to be added in a later patch | |||
grid.setDefaultHeaderRow(grid.getHeaderRow(0)); | |||
} | |||
} | |||
@Override | |||
public void setDataSource(DataSource<JsonObject> dataSource) { | |||
super.setDataSource(dataSource); | |||
@@ -228,6 +267,7 @@ public class GridConnector | |||
.containsValue(id) : "Column with given id already exists."; | |||
getWidget().addColumn(column); | |||
columnToIdMap.put(column, id); | |||
idToColumn.put(id, column); | |||
} | |||
/** | |||
@@ -241,7 +281,8 @@ public class GridConnector | |||
assert columnToIdMap | |||
.containsKey(column) : "Given Column does not exist."; | |||
getWidget().removeColumn(column); | |||
columnToIdMap.remove(column); | |||
String id = columnToIdMap.remove(column); | |||
idToColumn.remove(id); | |||
} | |||
@Override |
@@ -49,6 +49,8 @@ import com.vaadin.shared.ui.grid.GridConstants.Section; | |||
import com.vaadin.shared.ui.grid.GridServerRpc; | |||
import com.vaadin.shared.ui.grid.GridState; | |||
import com.vaadin.shared.ui.grid.HeightMode; | |||
import com.vaadin.shared.ui.grid.SectionState; | |||
import com.vaadin.ui.components.grid.Header; | |||
import com.vaadin.ui.renderers.AbstractRenderer; | |||
import com.vaadin.ui.renderers.Renderer; | |||
import com.vaadin.ui.renderers.TextRenderer; | |||
@@ -512,7 +514,7 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { | |||
if (rowKey != null) { | |||
item = getDataCommunicator().getKeyMapper().get(rowKey); | |||
} | |||
fireEvent(new GridContextClickEvent<T>(Grid.this, details, section, | |||
fireEvent(new GridContextClickEvent<>(Grid.this, details, section, | |||
rowIndex, item, getColumn(columnId))); | |||
} | |||
@@ -824,6 +826,15 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { | |||
super.extend(grid); | |||
} | |||
/** | |||
* Returns the identifier used with this Column in communication. | |||
* | |||
* @return the identifier string | |||
*/ | |||
public String getId() { | |||
return getState(false).id; | |||
} | |||
/** | |||
* Sets the identifier to use with this Column in communication. | |||
* | |||
@@ -1408,6 +1419,53 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { | |||
} | |||
} | |||
/** | |||
* A header row in a Grid. | |||
*/ | |||
public interface HeaderRow extends Serializable { | |||
/** | |||
* Returns the cell on this row corresponding to the given column id. | |||
* | |||
* @param columnId | |||
* the id of the column whose header cell to get | |||
* @return the header cell | |||
*/ | |||
public HeaderCell getCell(String columnId); | |||
/** | |||
* Returns the cell on this row corresponding to the given column. | |||
* | |||
* @param column | |||
* the column whose header cell to get | |||
* @return the header cell | |||
*/ | |||
public default HeaderCell getCell(Column<?, ?> column) { | |||
return getCell(column.getId()); | |||
} | |||
} | |||
/** | |||
* An individual cell on a Grid header row. | |||
*/ | |||
public interface HeaderCell extends Serializable { | |||
/** | |||
* Returns the textual caption of this cell. | |||
* | |||
* @return the header caption | |||
*/ | |||
public String getText(); | |||
/** | |||
* Sets the textual caption of this cell. | |||
* | |||
* @param text | |||
* the header caption to set | |||
*/ | |||
public void setText(String text); | |||
} | |||
private KeyMapper<Column<T, ?>> columnKeys = new KeyMapper<>(); | |||
private Set<Column<T, ?>> columnSet = new LinkedHashSet<>(); | |||
private List<SortOrder<Column<T, ?>>> sortOrder = new ArrayList<>(); | |||
@@ -1416,15 +1474,26 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { | |||
private StyleGenerator<T> styleGenerator = item -> null; | |||
private DescriptionGenerator<T> descriptionGenerator; | |||
private Header header = new Header() { | |||
@Override | |||
protected SectionState getState(boolean markAsDirty) { | |||
return Grid.this.getState(markAsDirty).header; | |||
} | |||
}; | |||
/** | |||
* Constructor for the {@link Grid} component. | |||
*/ | |||
public Grid() { | |||
setSelectionModel(new SingleSelection()); | |||
registerRpc(new GridServerRpcImpl()); | |||
appendHeaderRow(); | |||
detailsManager = new DetailsManager<>(); | |||
addExtension(detailsManager); | |||
addDataGenerator(detailsManager); | |||
addDataGenerator((item, json) -> { | |||
String styleName = styleGenerator.apply(item); | |||
if (styleName != null && !styleName.isEmpty()) { | |||
@@ -1455,8 +1524,6 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { | |||
* the value provider | |||
* @param renderer | |||
* the column value class | |||
* @param <T> | |||
* the type of this grid | |||
* @param <V> | |||
* the column value type | |||
* | |||
@@ -1467,13 +1534,23 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { | |||
public <V> Column<T, V> addColumn(String caption, | |||
Function<T, ? extends V> valueProvider, | |||
AbstractRenderer<? super T, V> renderer) { | |||
Column<T, V> column = new Column<>(caption, valueProvider, renderer); | |||
final Column<T, V> column = new Column<>(caption, valueProvider, | |||
renderer); | |||
final String columnId = columnKeys.key(column); | |||
column.extend(this); | |||
column.setId(columnKeys.key(column)); | |||
column.setId(columnId); | |||
columnSet.add(column); | |||
addDataGenerator(column); | |||
getHeader().addColumn(columnId); | |||
if (getHeaderRowCount() > 0) { | |||
// TODO Default header API to be added in a later patch | |||
HeaderRow defaultHeader = getHeaderRow(0); | |||
defaultHeader.getCell(columnId).setText(caption); | |||
} | |||
return column; | |||
} | |||
@@ -1762,6 +1839,130 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { | |||
return descriptionGenerator; | |||
} | |||
// | |||
// HEADER AND FOOTER | |||
// | |||
/** | |||
* Returns the header row at the given index. | |||
* | |||
* @param rowIndex | |||
* the index of the row, where the topmost row has index zero | |||
* @return the header row at the index | |||
* @throws IndexOutOfBoundsException | |||
* if {@code rowIndex < 0 || rowIndex >= getHeaderRowCount()} | |||
*/ | |||
public HeaderRow getHeaderRow(int rowIndex) { | |||
return getHeader().getRow(rowIndex); | |||
} | |||
/** | |||
* Gets the number of rows in the header section. | |||
* | |||
* @return the number of header rows | |||
*/ | |||
public int getHeaderRowCount() { | |||
return header.getRowCount(); | |||
} | |||
/** | |||
* Inserts a new row at the given position to the header section. Shifts the | |||
* row currently at that position and any subsequent rows down (adds one to | |||
* their indices). Inserting at {@link #getHeaderRowCount()} appends the row | |||
* at the bottom of the header. | |||
* | |||
* @param index | |||
* the index at which to insert the row, where the topmost row | |||
* has index zero | |||
* @return the inserted header row | |||
* | |||
* @throws IndexOutOfBoundsException | |||
* if {@code rowIndex < 0 || rowIndex > getHeaderRowCount()} | |||
* | |||
* @see #appendHeaderRow() | |||
* @see #prependHeaderRow() | |||
* @see #removeHeaderRow(HeaderRow) | |||
* @see #removeHeaderRow(int) | |||
*/ | |||
public HeaderRow addHeaderRowAt(int index) { | |||
return getHeader().addRowAt(index); | |||
} | |||
/** | |||
* Adds a new row at the bottom of the header section. | |||
* | |||
* @return the appended header row | |||
* | |||
* @see #prependHeaderRow() | |||
* @see #addHeaderRowAt(int) | |||
* @see #removeHeaderRow(HeaderRow) | |||
* @see #removeHeaderRow(int) | |||
*/ | |||
public HeaderRow appendHeaderRow() { | |||
return addHeaderRowAt(getHeaderRowCount()); | |||
} | |||
/** | |||
* Adds a new row at the top of the header section. | |||
* | |||
* @return the prepended header row | |||
* | |||
* @see #appendHeaderRow() | |||
* @see #addHeaderRowAt(int) | |||
* @see #removeHeaderRow(HeaderRow) | |||
* @see #removeHeaderRow(int) | |||
*/ | |||
public HeaderRow prependHeaderRow() { | |||
return addHeaderRowAt(0); | |||
} | |||
/** | |||
* Removes the given row from the header section. | |||
* | |||
* @param row | |||
* the header row to be removed, not null | |||
* | |||
* @throws IllegalArgumentException | |||
* if the header does not contain the row | |||
* | |||
* @see #removeHeaderRow(int) | |||
* @see #addHeaderRowAt(int) | |||
* @see #appendHeaderRow() | |||
* @see #prependHeaderRow() | |||
*/ | |||
public void removeHeaderRow(HeaderRow row) { | |||
getHeader().removeRow(row); | |||
} | |||
/** | |||
* Removes the row at the given position from the header section. | |||
* | |||
* @param rowIndex | |||
* the index of the row to remove, where the topmost row has | |||
* index zero | |||
* | |||
* @throws IndexOutOfBoundsException | |||
* if {@code rowIndex < 0 || rowIndex >= getHeaderRowCount()} | |||
* | |||
* @see #removeHeaderRow(HeaderRow) | |||
* @see #addHeaderRowAt(int) | |||
* @see #appendHeaderRow() | |||
* @see #prependHeaderRow() | |||
*/ | |||
public void removeHeaderRow(int rowIndex) { | |||
getHeader().removeRow(rowIndex); | |||
} | |||
/** | |||
* Returns the header section of this grid. The default header contains a | |||
* single row displaying the column captions. | |||
* | |||
* @return the header section | |||
*/ | |||
protected Header getHeader() { | |||
return header; | |||
} | |||
/** | |||
* Registers a new column resize listener. | |||
* |
@@ -0,0 +1,57 @@ | |||
/* | |||
* 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.ui.components.grid; | |||
import com.vaadin.ui.Grid; | |||
/** | |||
* Represents the header section of a Grid. | |||
*/ | |||
public abstract class Header extends StaticSection<Header.Row> { | |||
public class Row extends StaticSection.StaticRow<Row.Cell> | |||
implements Grid.HeaderRow { | |||
public class Cell extends StaticSection.StaticCell implements | |||
Grid.HeaderCell { | |||
protected Cell() { | |||
super(Row.this); | |||
} | |||
} | |||
/** | |||
* @param section | |||
*/ | |||
protected Row() { | |||
super(Header.this); | |||
} | |||
@Override | |||
protected Cell createCell() { | |||
return new Cell(); | |||
} | |||
@Override | |||
protected String getCellTagName() { | |||
return "th"; | |||
} | |||
} | |||
@Override | |||
public Row createRow() { | |||
return new Row(); | |||
} | |||
} |
@@ -0,0 +1,307 @@ | |||
/* | |||
* 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.ui.components.grid; | |||
import java.io.Serializable; | |||
import java.util.ArrayList; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import com.vaadin.shared.ui.grid.SectionState; | |||
import com.vaadin.shared.ui.grid.SectionState.CellState; | |||
import com.vaadin.shared.ui.grid.SectionState.RowState; | |||
/** | |||
* Represents the header or footer section of a Grid. | |||
* | |||
* @author Vaadin Ltd. | |||
* | |||
* @param <ROW> | |||
* the type of the rows in the section | |||
* | |||
* @since 8.0 | |||
*/ | |||
public abstract class StaticSection<ROW extends StaticSection.StaticRow<?>> | |||
implements Serializable { | |||
/** | |||
* Abstract base class for Grid header and footer rows. | |||
* | |||
* @param <CELL> | |||
* the type of the cells in the row | |||
*/ | |||
public abstract static class StaticRow<CELL extends StaticCell> | |||
implements Serializable { | |||
private RowState rowState = new RowState(); | |||
private StaticSection<?> section; | |||
private Map<Object, CELL> cells = new LinkedHashMap<>(); | |||
/** | |||
* Creates a new row belonging to the given section. | |||
* | |||
* @param section | |||
* the section of the row | |||
*/ | |||
protected StaticRow(StaticSection<?> section) { | |||
this.section = section; | |||
} | |||
/** | |||
* Creates and returns a new instance of the cell type. | |||
* | |||
* @return the created cell | |||
*/ | |||
protected abstract CELL createCell(); | |||
/** | |||
* Returns the declarative tag name used for the cells in this row. | |||
* | |||
* @return the cell tag name | |||
*/ | |||
protected abstract String getCellTagName(); | |||
/** | |||
* Adds a cell to this section, corresponding to the given column id. | |||
* | |||
* @param columnId | |||
* the id of the column for which to add a cell | |||
*/ | |||
protected void addCell(String columnId) { | |||
CELL cell = createCell(); | |||
cell.setColumnId(columnId); | |||
cells.put(columnId, cell); | |||
rowState.cells.put(columnId, cell.getCellState()); | |||
} | |||
/** | |||
* Removes the cell from this section that corresponds to the given | |||
* column id. If there is no such cell, does nothing. | |||
* | |||
* @param columnId | |||
* the id of the column from which to remove the cell | |||
*/ | |||
protected void removeCell(Object columnId) { | |||
CELL cell = cells.remove(columnId); | |||
if (cell != null) { | |||
rowState.cells.remove(cell.getCellState()); | |||
} | |||
} | |||
/** | |||
* Returns the shared state of this row. | |||
* | |||
* @return the row state | |||
*/ | |||
protected RowState getRowState() { | |||
return rowState; | |||
} | |||
/** | |||
* Returns the cell in this section that corresponds to the given column | |||
* id. | |||
* | |||
* @param columnId | |||
* the id of the column | |||
* @return the cell for the given column or null if not found | |||
*/ | |||
public CELL getCell(String columnId) { | |||
CELL cell = cells.get(columnId); | |||
return cell; | |||
} | |||
} | |||
/** | |||
* A header or footer cell. Has a simple textual caption. | |||
*/ | |||
abstract static class StaticCell implements Serializable { | |||
private CellState cellState = new CellState(); | |||
private StaticRow<?> row; | |||
protected StaticCell(StaticRow<?> row) { | |||
this.row = row; | |||
} | |||
void setColumnId(String id) { | |||
cellState.columnId = id; | |||
} | |||
String getColumnId() { | |||
return cellState.columnId; | |||
} | |||
/** | |||
* Gets the row where this cell is. | |||
* | |||
* @return row for this cell | |||
*/ | |||
public StaticRow<?> getRow() { | |||
return row; | |||
} | |||
/** | |||
* Returns the shared state of this cell. | |||
* | |||
* @return the cell state | |||
*/ | |||
protected CellState getCellState() { | |||
return cellState; | |||
} | |||
/** | |||
* Sets the textual caption of this cell. | |||
* | |||
* @param text | |||
* a plain text caption, not null | |||
*/ | |||
public void setText(String text) { | |||
Objects.requireNonNull(text, "text cannot be null"); | |||
cellState.text = text; | |||
row.section.markAsDirty(); | |||
} | |||
/** | |||
* Returns the textual caption of this cell. | |||
* | |||
* @return the plain text caption | |||
*/ | |||
public String getText() { | |||
return cellState.text; | |||
} | |||
} | |||
private List<ROW> rows = new ArrayList<>(); | |||
/** | |||
* Creates a new row instance. | |||
* | |||
* @return the new row | |||
*/ | |||
protected abstract ROW createRow(); | |||
/** | |||
* Returns the shared state of this section. | |||
* | |||
* @param markAsDirty | |||
* {@code true} to mark the state as modified, {@code false} | |||
* otherwise | |||
* @return the section state | |||
*/ | |||
protected abstract SectionState getState(boolean markAsDirty); | |||
/** | |||
* Marks the state of this section as modified. | |||
*/ | |||
protected void markAsDirty() { | |||
getState(true); | |||
} | |||
/** | |||
* Adds a new row at the given index. | |||
* | |||
* @param index | |||
* the index of the new row | |||
* @return the added row | |||
* @throws IndexOutOfBoundsException | |||
* if {@code index < 0 || index > getRowCount()} | |||
*/ | |||
public ROW addRowAt(int index) { | |||
ROW row = createRow(); | |||
rows.add(index, row); | |||
getState(true).rows.add(index, row.getRowState()); | |||
return row; | |||
} | |||
/** | |||
* Removes the row at the given index. | |||
* | |||
* @param index | |||
* the index of the row to remove | |||
* @throws IndexOutOfBoundsException | |||
* if {@code index < 0 || index >= getRowCount()} | |||
*/ | |||
public void removeRow(int index) { | |||
rows.remove(index); | |||
getState(true).rows.remove(index); | |||
} | |||
/** | |||
* Removes the given row from this section. | |||
* | |||
* @param row | |||
* the row to remove, not null | |||
* @throws IllegalArgumentException | |||
* if this section does not contain the row | |||
*/ | |||
public void removeRow(Object row) { | |||
Objects.requireNonNull(row, "row cannot be null"); | |||
int index = rows.indexOf(row); | |||
if (index < 0) { | |||
throw new IllegalArgumentException( | |||
"Section does not contain the given row"); | |||
} | |||
removeRow(index); | |||
} | |||
/** | |||
* Returns the row at the given index. | |||
* | |||
* @param index | |||
* the index of the row | |||
* @return the row at the index | |||
* @throws IndexOutOfBoundsException | |||
* if {@code index < 0 || index >= getRowCount()} | |||
*/ | |||
public ROW getRow(int index) { | |||
return rows.get(index); | |||
} | |||
/** | |||
* Returns the number of rows in this section. | |||
* | |||
* @return the number of rows | |||
*/ | |||
public int getRowCount() { | |||
return rows.size(); | |||
} | |||
/** | |||
* Adds a cell corresponding to the given column id to this section. | |||
* | |||
* @param columnId | |||
* the id of the column for which to add a cell | |||
*/ | |||
public void addColumn(String columnId) { | |||
for (ROW row : rows) { | |||
row.addCell(columnId); | |||
} | |||
} | |||
/** | |||
* Removes the cell corresponding to the given column id. | |||
* | |||
* @param columnId | |||
* the id of the column whose cell to remove | |||
*/ | |||
public void removeColumn(String columnId) { | |||
for (ROW row : rows) { | |||
row.removeCell(columnId); | |||
} | |||
} | |||
} |
@@ -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.server.component.grid; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertSame; | |||
import static org.junit.Assert.fail; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import com.vaadin.ui.Grid; | |||
import com.vaadin.ui.Grid.Column; | |||
import com.vaadin.ui.Grid.HeaderRow; | |||
public class GridHeaderFooterTest { | |||
private Grid<String> grid; | |||
private Column<?, ?> column1, column2; | |||
@Before | |||
public void setUp() { | |||
grid = new Grid<>(); | |||
column1 = grid.addColumn("First", s -> s.substring(0, 1)); | |||
column2 = grid.addColumn("Rest", s -> s.substring(1)); | |||
} | |||
@Test | |||
public void initialState_hasDefaultHeader() { | |||
assertEquals(1, grid.getHeaderRowCount()); | |||
HeaderRow defaultHeader = grid.getHeaderRow(0); | |||
assertEquals("First", defaultHeader.getCell(column1).getText()); | |||
assertEquals("Rest", defaultHeader.getCell(column2).getText()); | |||
} | |||
@Test | |||
public void initialState_defaultHeaderRemovable() { | |||
grid.removeHeaderRow(0); | |||
assertEquals(0, grid.getHeaderRowCount()); | |||
} | |||
@Test | |||
public void appendHeaderRow_addedToBottom() { | |||
HeaderRow defaultRow = grid.getHeaderRow(0); | |||
HeaderRow addedRow = grid.appendHeaderRow(); | |||
assertSame(defaultRow, grid.getHeaderRow(0)); | |||
assertSame(addedRow, grid.getHeaderRow(1)); | |||
} | |||
@Test | |||
public void prependHeaderRow_addedToTop() { | |||
HeaderRow defaultRow = grid.getHeaderRow(0); | |||
HeaderRow addedRow = grid.prependHeaderRow(); | |||
assertSame(addedRow, grid.getHeaderRow(0)); | |||
assertSame(defaultRow, grid.getHeaderRow(1)); | |||
} | |||
@Test | |||
public void addHeaderRowAtZero_addedToTop() { | |||
HeaderRow defaultRow = grid.getHeaderRow(0); | |||
HeaderRow addedRow = grid.addHeaderRowAt(0); | |||
assertSame(addedRow, grid.getHeaderRow(0)); | |||
assertSame(defaultRow, grid.getHeaderRow(1)); | |||
} | |||
@Test | |||
public void addHeaderRowAtRowCount_addedToBottom() { | |||
HeaderRow defaultRow = grid.getHeaderRow(0); | |||
HeaderRow addedRow = grid.addHeaderRowAt(grid.getHeaderRowCount()); | |||
assertSame(defaultRow, grid.getHeaderRow(0)); | |||
assertSame(addedRow, grid.getHeaderRow(1)); | |||
} | |||
@Test | |||
public void removeExistingHeaderRow_removed() { | |||
HeaderRow defaultRow = grid.getHeaderRow(0); | |||
HeaderRow addedRow = grid.appendHeaderRow(); | |||
grid.removeHeaderRow(addedRow); | |||
assertEquals(1, grid.getHeaderRowCount()); | |||
assertSame(defaultRow, grid.getHeaderRow(0)); | |||
} | |||
@Test | |||
public void removeDefaultHeaderRow_removed() { | |||
HeaderRow defaultRow = grid.getHeaderRow(0); | |||
HeaderRow addedRow = grid.appendHeaderRow(); | |||
grid.removeHeaderRow(defaultRow); | |||
assertEquals(1, grid.getHeaderRowCount()); | |||
assertSame(addedRow, grid.getHeaderRow(0)); | |||
} | |||
@Test(expected = IndexOutOfBoundsException.class) | |||
public void getHeaderRowNegativeIndex_throws() { | |||
grid.getHeaderRow(-1); | |||
} | |||
@Test(expected = IndexOutOfBoundsException.class) | |||
public void getHeaderRowIndexTooLarge_throws() { | |||
grid.appendHeaderRow(); | |||
grid.getHeaderRow(2); | |||
} | |||
@Test(expected = IndexOutOfBoundsException.class) | |||
public void addHeaderRowAtNegativeIndex_throws() { | |||
grid.addHeaderRowAt(-1); | |||
} | |||
@Test(expected = IndexOutOfBoundsException.class) | |||
public void addHeaderRowAtIndexTooLarge_throws() { | |||
grid.addHeaderRowAt(2); | |||
} | |||
@Test(expected = IndexOutOfBoundsException.class) | |||
public void removeHeaderRowNegativeIndex_throws() { | |||
grid.removeHeaderRow(-1); | |||
} | |||
@Test(expected = IndexOutOfBoundsException.class) | |||
public void removeHeaderRowIndexTooLarge_throws() { | |||
grid.removeHeaderRow(1); | |||
} | |||
@Test(expected = IllegalArgumentException.class) | |||
public void removeNonExistingHeaderRow_throws() { | |||
HeaderRow row = grid.getHeaderRow(0); | |||
try { | |||
grid.removeHeaderRow(row); | |||
} catch (Exception e) { | |||
fail("unexpected exception: " + e); | |||
} | |||
grid.removeHeaderRow(row); | |||
} | |||
} |
@@ -99,6 +99,9 @@ public class GridState extends AbstractSingleSelectState { | |||
primaryStyleName = "v-grid"; | |||
} | |||
/** The state of the header section. */ | |||
public SectionState header = new SectionState(); | |||
/** | |||
* Column order in grid. | |||
*/ |
@@ -0,0 +1,57 @@ | |||
/* | |||
* 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.shared.ui.grid; | |||
import java.io.Serializable; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
/** | |||
* Shared state for Grid headers and footers. | |||
* | |||
* @author Vaadin Ltd | |||
* @since 7.4 | |||
*/ | |||
public class SectionState implements Serializable { | |||
/** The state of a header or footer row. */ | |||
public static class RowState implements Serializable { | |||
/** The map from column ids to the cells in this row. */ | |||
public Map<String, CellState> cells = new HashMap<>(); | |||
/** | |||
* Whether this row is the default header row. Always false for footer | |||
* rows. | |||
*/ | |||
public boolean defaultHeader = false; | |||
} | |||
/** The state of a header or footer cell. */ | |||
public static class CellState implements Serializable { | |||
/** The textual caption of this cell. */ | |||
public String text; | |||
/** The id of the column that this cell belongs to. */ | |||
public String columnId; | |||
} | |||
/** The rows in this section. */ | |||
public List<RowState> rows = new ArrayList<>(); | |||
} |
@@ -2,6 +2,7 @@ package com.vaadin.tests.components.grid; | |||
import java.util.Arrays; | |||
import com.vaadin.annotations.Widgetset; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.tests.components.AbstractTestUI; | |||
import com.vaadin.tests.data.bean.Person; | |||
@@ -11,6 +12,7 @@ import com.vaadin.ui.Label; | |||
import com.vaadin.ui.TextField; | |||
import com.vaadin.ui.renderers.NumberRenderer; | |||
@Widgetset("com.vaadin.DefaultWidgetSet") | |||
public class GridColumnResizing extends AbstractTestUI { | |||
@Override |
@@ -33,6 +33,8 @@ import com.vaadin.ui.renderers.ProgressBarRenderer; | |||
@Widgetset("com.vaadin.DefaultWidgetSet") | |||
public class GridBasics extends AbstractTestUIWithLog { | |||
public static final String[] COLUMN_CAPTIONS = { "Column 0", "Column 1", "Column 2", "Row Number", "Date", "HTML String", "Big Random", "Small Random" }; | |||
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"; | |||
@@ -128,21 +130,21 @@ public class GridBasics extends AbstractTestUIWithLog { | |||
grid = new Grid<>(); | |||
grid.setItems(data); | |||
grid.addColumn("Column 0", | |||
grid.addColumn(COLUMN_CAPTIONS[0], | |||
dataObj -> "(" + dataObj.getRowNumber() + ", 0)"); | |||
grid.addColumn("Column 1", | |||
grid.addColumn(COLUMN_CAPTIONS[1], | |||
dataObj -> "(" + dataObj.getRowNumber() + ", 1)"); | |||
grid.addColumn("Column 2", | |||
grid.addColumn(COLUMN_CAPTIONS[2], | |||
dataObj -> "(" + dataObj.getRowNumber() + ", 2)"); | |||
grid.addColumn("Row Number", DataObject::getRowNumber, | |||
grid.addColumn(COLUMN_CAPTIONS[3], DataObject::getRowNumber, | |||
new NumberRenderer()); | |||
grid.addColumn("Date", DataObject::getDate, new DateRenderer()); | |||
grid.addColumn("HTML String", DataObject::getHtmlString, | |||
grid.addColumn(COLUMN_CAPTIONS[4], DataObject::getDate, new DateRenderer()); | |||
grid.addColumn(COLUMN_CAPTIONS[5], DataObject::getHtmlString, | |||
new HtmlRenderer()); | |||
grid.addColumn("Big Random", DataObject::getBigRandom, | |||
grid.addColumn(COLUMN_CAPTIONS[6], DataObject::getBigRandom, | |||
new NumberRenderer()); | |||
grid.addColumn("Small Random", data -> data.getSmallRandom() / 5d, | |||
grid.addColumn(COLUMN_CAPTIONS[7], data -> data.getSmallRandom() / 5d, | |||
new ProgressBarRenderer()); | |||
grid.addSelectionListener(e -> log("Selected: " + e.getValue())); | |||
@@ -159,6 +161,7 @@ public class GridBasics extends AbstractTestUIWithLog { | |||
createSizeMenu(componentMenu.addItem("Size", null)); | |||
createDetailsMenu(componentMenu.addItem("Details", null)); | |||
createBodyMenu(componentMenu.addItem("Body rows", null)); | |||
createHeaderMenu(componentMenu.addItem("Header", null)); | |||
return menu; | |||
} | |||
@@ -293,6 +296,18 @@ public class GridBasics extends AbstractTestUIWithLog { | |||
}); | |||
} | |||
private void createHeaderMenu(MenuItem headerMenu) { | |||
headerMenu.addItem("Append header row", menuItem -> { | |||
grid.appendHeaderRow(); | |||
}); | |||
headerMenu.addItem("Prepend header row", menuItem -> { | |||
grid.prependHeaderRow(); | |||
}); | |||
headerMenu.addItem("Remove first header row", menuItem -> { | |||
grid.removeHeaderRow(0); | |||
}); | |||
} | |||
/* DetailsGenerator related things */ | |||
private void createDetailsMenu(MenuItem detailsMenu) { |
@@ -0,0 +1,69 @@ | |||
/* | |||
* 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.assertEquals; | |||
import java.util.List; | |||
import org.junit.Test; | |||
import com.vaadin.testbench.By; | |||
import com.vaadin.testbench.elements.GridElement.GridCellElement; | |||
public class GridHeaderFooterTest extends GridBasicsTest { | |||
@Test | |||
public void initialState_defaultHeaderPresent() { | |||
assertEquals(1, getGridElement().getHeaderCount()); | |||
final String[] captions = GridBasics.COLUMN_CAPTIONS; | |||
List<GridCellElement> headerCells = getGridElement().getHeaderCells(0); | |||
assertEquals(captions.length, headerCells.size()); | |||
for (int i = 0; i < headerCells.size(); i++) { | |||
assertText(captions[i], headerCells.get(i)); | |||
} | |||
} | |||
@Test | |||
public void appendHeaderRow_addedToBottom() { | |||
selectMenuPath("Component", "Header", "Append header row"); | |||
assertEquals(2, getGridElement().getHeaderCount()); | |||
} | |||
@Test | |||
public void prependHeaderRow_addedToBottom() { | |||
selectMenuPath("Component", "Header", "Prepend header row"); | |||
assertEquals(2, getGridElement().getHeaderCount()); | |||
} | |||
@Test | |||
public void removeDefaultHeaderRow_noHeaderRows() { | |||
selectMenuPath("Component", "Header", "Remove first header row"); | |||
assertEquals(0, getGridElement().getHeaderCount()); | |||
} | |||
protected static void assertText(String expected, GridCellElement e) { | |||
// TBE.getText returns "" if the element is scrolled out of view | |||
String actual = e.findElement(By.tagName("div")).getAttribute( | |||
"innerHTML"); | |||
assertEquals(expected, actual); | |||
} | |||
} |