Skip to content

Commit

Permalink
Grid merging footer cells
Browse files Browse the repository at this point in the history
Change-Id: I24895c7ae602ffc9a7812dcc441e99ac670356e2
  • Loading branch information
elmot committed Nov 29, 2016
1 parent 5ab9903 commit 5eaac7a
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 59 deletions.
Expand Up @@ -232,22 +232,26 @@ void updateHeader() {
grid.setDefaultHeaderRow(row);
}

rowState.cells.forEach((columnId, cellState) -> {
updateHeaderCellFromState(row.getCell(getColumn(columnId)),
cellState);
});
for (Map.Entry<CellState, Set<String>> cellGroupEntry : rowState.cellGroups.entrySet()) {
Set<String> group = cellGroupEntry.getValue();

Grid.Column<?, ?>[] columns =
group.stream().map(idToColumn::get).toArray(size->new Grid.Column<?, ?>[size]);
// Set state to be the same as first in group.
updateHeaderCellFromState(row.join(columns), cellGroupEntry.getKey());
}
updateStaticRow(rowState, row);
}
}

private void updateStaticRow(RowState rowState, Grid.StaticSection.StaticRow row) {
rowState.cells.forEach((columnId, cellState) -> {
updateStaticCellFromState(row.getCell(getColumn(columnId)),
cellState);
});
for (Map.Entry<CellState, Set<String>> cellGroupEntry : rowState.cellGroups.entrySet()) {
Set<String> group = cellGroupEntry.getValue();

Grid.Column<?, ?>[] columns =
group.stream().map(idToColumn::get).toArray(size->new Grid.Column<?, ?>[size]);
// Set state to be the same as first in group.
updateStaticCellFromState(row.join(columns), cellGroupEntry.getKey());
}
}

private void updateHeaderCellFromState(HeaderCell cell,
private void updateStaticCellFromState(Grid.StaticSection.StaticCell cell,
CellState cellState) {
switch (cellState.type) {
case TEXT:
Expand Down Expand Up @@ -288,39 +292,10 @@ void updateFooter() {
for (RowState rowState : state.rows) {
FooterRow row = grid.appendFooterRow();

rowState.cells.forEach((columnId, cellState) -> {
updateFooterCellFromState(row.getCell(getColumn(columnId)),
cellState);
});
updateStaticRow(rowState, row);
}
}

private void updateFooterCellFromState(FooterCell cell,
CellState cellState) {
switch (cellState.type) {
case TEXT:
cell.setText(cellState.text);
break;
case HTML:
cell.setHtml(cellState.html);
break;
case WIDGET:
ComponentConnector connector = (ComponentConnector) cellState.connector;
if (connector != null) {
cell.setWidget(connector.getWidget());
} else {
// This happens if you do setVisible(false) on the component on
// the server side
cell.setWidget(null);
}
break;
default:
throw new IllegalStateException(
"unexpected cell type: " + cellState.type);
}
cell.setStyleName(cellState.styleName);
}

@Override
public void setDataSource(DataSource<JsonObject> dataSource) {
super.setDataSource(dataSource);
Expand Down
61 changes: 53 additions & 8 deletions server/src/main/java/com/vaadin/ui/Grid.java
Expand Up @@ -1672,20 +1672,30 @@ public default HeaderCell getCell(Column<?, ?> column) {
}

/**
* Merges columns cells in a row
* Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead.
* The cell has a width of all merged cells together, inherits styles of the first merged cell
* but has empty caption.
*
* @param cells
* The cells to merge. Must be from the same row.
* @return The remaining visible cell after the merge
* @param cellsToMerge
* the cells which should be merged. The cells should not be merged to any other cell set.
* @return the remaining visible cell after the merge
*
* @see #join(Grid.HeaderCell...)
* @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption
*/
HeaderCell join(Set<HeaderCell> cellsToMerge);

/**
* Merges columns cells in a row
* Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead.
* The cell has a width of all merged cells together, inherits styles of the first merged cell
* but has empty caption.
*
* @param cellsToMerge
* the cells which should be merged. The cells should not be merged to any other cell set.
* @return the remaining visible cell after the merge
*
* @param cells
* The cells to merge. Must be from the same row.
* @return The remaining visible cell after the merge
* @see #join(Set)
* @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption
*/
HeaderCell join(HeaderCell... cellsToMerge);

Expand Down Expand Up @@ -1785,6 +1795,34 @@ public interface FooterRow extends Serializable {
public default FooterCell getCell(Column<?, ?> column) {
return getCell(column.getId());
}

/**
* Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead.
* The cell has a width of all merged cells together, inherits styles of the first merged cell
* but has empty caption.
*
* @param cellsToMerge
* the cells which should be merged. The cells should not be merged to any other cell set.
* @return the remaining visible cell after the merge
*
* @see #join(Grid.FooterCell...)
* @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption
*/
FooterCell join(Set<FooterCell> cellsToMerge);

/**
* Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead.
* The cell has a width of all merged cells together, inherits styles of the first merged cell
* but has empty caption.
*
* @param cellsToMerge
* the cells which should be merged. The cells should not be merged to any other cell set.
* @return the remaining visible cell after the merge
*
* @see #join(Set)
* @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption
*/
FooterCell join(FooterCell ... cellsToMerge);
}

/**
Expand Down Expand Up @@ -1844,6 +1882,13 @@ public interface FooterCell extends Serializable {
* @return cell content type
*/
public GridStaticCellType getCellType();

/**
* Gets the column id where this cell is.
*
* @return column id for this cell
*/
public String getColumnId();
}

/**
Expand Down
54 changes: 54 additions & 0 deletions server/src/main/java/com/vaadin/ui/components/grid/Footer.java
Expand Up @@ -17,6 +17,10 @@

import com.vaadin.ui.Grid;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
* Represents the footer section of a Grid.
*
Expand Down Expand Up @@ -61,6 +65,56 @@ protected Cell createCell() {
protected String getCellTagName() {
return "td";
}

/**
* Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead.
* The cell has a width of all merged cells together, inherits styles of the first merged cell
* but has empty caption.
*
* @param cellsToMerge
* the cells which should be merged. The cells should not be merged to any other cell set.
* @return the remaining visible cell after the merge
*
* @see #join(Grid.FooterCell...)
* @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption
*/
@Override
public Grid.FooterCell join(Set<Grid.FooterCell> cellsToMerge) {
for (Grid.FooterCell cell : cellsToMerge) {
checkIfAlreadyMerged(cell.getColumnId());
}

// Create new cell data for the group
Cell newCell = createCell();

Set<String> columnGroup = new HashSet<>();
for (Grid.FooterCell cell : cellsToMerge) {
columnGroup.add(cell.getColumnId());
}
addMergedCell(newCell, columnGroup);
markAsDirty();
return newCell;
}

/**
* Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead.
* The cell has a width of all merged cells together, inherits styles of the first merged cell
* but has empty caption.
*
* @param cellsToMerge
* the cells which should be merged. The cells should not be merged to any other cell set.
* @return the remaining visible cell after the merge
*
* @see #join(Set)
* @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption
*/
@Override
public Grid.FooterCell join(Grid.FooterCell... cellsToMerge) {
Set<Grid.FooterCell> footerCells = new HashSet<>(Arrays.asList(cellsToMerge));
return join(footerCells);
}


}

@Override
Expand Down
18 changes: 14 additions & 4 deletions server/src/main/java/com/vaadin/ui/components/grid/Header.java
Expand Up @@ -87,11 +87,16 @@ protected void setDefault(boolean defaultHeader) {
}

/**
* Merges columns cells in a row
* Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead.
* The cell has a width of all merged cells together, inherits styles of the first merged cell
* but has empty caption.
*
* @param cellsToMerge
* the cells which should be merged
* the cells which should be merged. The cells should not be merged to any other cell set.
* @return the remaining visible cell after the merge
*
* @see #join(Grid.HeaderCell...)
* @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption
*/
@Override
public Grid.HeaderCell join(Set<Grid.HeaderCell> cellsToMerge) {
Expand All @@ -112,11 +117,16 @@ public Grid.HeaderCell join(Set<Grid.HeaderCell> cellsToMerge) {
}

/**
* Merges columns cells in a row
* Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead.
* The cell has a width of all merged cells together, inherits styles of the first merged cell
* but has empty caption.
*
* @param cellsToMerge
* the cells which should be merged
* the cells which should be merged. The cells should not be merged to any other cell set.
* @return the remaining visible cell after the merge
*
* @see #join(Set)
* @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption
*/
@Override
public Grid.HeaderCell join(Grid.HeaderCell... cellsToMerge) {
Expand Down
Expand Up @@ -547,6 +547,16 @@ private void createHeaderMenu(MenuItem headerMenu) {
headerRow.join(toMerge).setText(jointCellText);
}

private void mergeFooterСells(int rowIndex, String jointCellText, int... columnIndexes) {
FooterRow footerRow = grid.getFooterRow(rowIndex);
List<Column<DataObject, ?>> columns = grid.getColumns();
Set<Grid.FooterCell> toMerge = new HashSet<>();
for (int columnIndex : columnIndexes) {
toMerge.add(footerRow.getCell(columns.get(columnIndex)));
}
footerRow.join(toMerge).setText(jointCellText);
}

private void createFooterMenu(MenuItem footerMenu) {
footerMenu.addItem("Add default footer row", menuItem -> {
FooterRow defaultFooter = grid.appendFooterRow();
Expand Down Expand Up @@ -574,6 +584,15 @@ private void createFooterMenu(MenuItem footerMenu) {
footerMenu.addItem("Remove first footer row", menuItem -> {
grid.removeFooterRow(0);
});
footerMenu.addItem("Merge Footer Cells [0,0..1]", menuItem -> {
mergeFooterСells(0, "0+1", 0, 1);
});
footerMenu.addItem("Merge Footer Cells [1,1..3]", menuItem -> {
mergeFooterСells(1, "1+2+3", 1, 2, 3);
});
footerMenu.addItem("Merge Footer Cells [0,6..7]", menuItem -> {
mergeFooterСells(0, "6+7", 6, 7);
});
}

/* DetailsGenerator related things */
Expand Down
Expand Up @@ -265,16 +265,25 @@ public void testHeaderMergedRemoveColumn() {
selectMenuPath("Component", "Header", "Append header row");
selectMenuPath("Component", "Header", "Merge Header Cells [0,0..1]");

GridCellElement c00 = getGridElement().getHeaderCell(0, 0);
assertEquals("0+1", c00.getText());
assertEquals("Colspan of cell [0,0]", "2", c00.getAttribute("colspan"));
selectMenuPath("Component", "Footer", "Append footer row");
selectMenuPath("Component", "Footer", "Merge Footer Cells [0,0..1]");

checkMergedHeaderFooter();

selectMenuPath("Component", "Columns", "Column 1", "Remove");
selectMenuPath("Component", "Header", "Append header row");
selectMenuPath("Component", "Footer", "Append footer row");

checkHeaderAfterDelete();
checkFooterAfterDelete();

}

private void checkHeaderAfterDelete() {
GridCellElement c00;
c00 = getGridElement().getHeaderCell(0, 0);
assertEquals("Column 0", c00.getText());
assertEquals("Colspan of cell [0,0]", "1", c00.getAttribute("colspan"));
assertEquals("Colspan of header cell [0,0]", "1", c00.getAttribute("colspan"));

GridCellElement c01 = getGridElement().getHeaderCell(0, 1);
assertEquals("Column 2", c01.getText());
Expand All @@ -290,8 +299,33 @@ public void testHeaderMergedRemoveColumn() {

GridCellElement c21 = getGridElement().getHeaderCell(2, 1);
assertEquals("Header cell 1", c21.getText());
}

private void checkFooterAfterDelete() {
GridCellElement c10;
//footer has an invisible first row
c10 = getGridElement().getFooterCell(1, 0);
assertEquals("Footer cell 0", c10.getText());
assertEquals("Colspan of footer cell [0,0]", "1", c10.getAttribute("colspan"));

GridCellElement c11 = getGridElement().getFooterCell(1, 1);
assertEquals("Footer cell 2", c11.getText());

GridCellElement c20 = getGridElement().getFooterCell(2, 0);
assertEquals("Footer cell 0", c20.getText());

GridCellElement c21 = getGridElement().getFooterCell(2, 1);
assertEquals("Footer cell 1", c21.getText());
}

private void checkMergedHeaderFooter() {
GridCellElement c00 = getGridElement().getHeaderCell(0, 0);
assertEquals("0+1", c00.getText());
assertEquals("Colspan of header cell [0,0]", "2", c00.getAttribute("colspan"));

c00 = getGridElement().getFooterCell(0, 0);
assertEquals("0+1", c00.getText());
assertEquals("Colspan of footer cell [0,0]", "2", c00.getAttribute("colspan"));
}

@Test
Expand All @@ -315,6 +349,27 @@ public void testHeaderMerge() {

}

@Test
public void testFooterMerge() {
selectMenuPath("Component", "Footer", "Append footer row");
selectMenuPath("Component", "Footer", "Merge Footer Cells [0,0..1]");
selectMenuPath("Component", "Footer", "Merge Footer Cells [1,1..3]");
selectMenuPath("Component", "Footer", "Merge Footer Cells [0,6..7]");

GridCellElement mergedCell1 = getGridElement().getFooterCell(0, 0);
assertEquals("0+1", mergedCell1.getText());
assertEquals("Colspan, cell [0,0]", "2", mergedCell1.getAttribute("colspan"));

GridCellElement mergedCell2 = getGridElement().getFooterCell(1, 1);
assertEquals("1+2+3", mergedCell2.getText());
assertEquals("Colspan of cell [1,1]", "3", mergedCell2.getAttribute("colspan"));

GridCellElement mergedCell3 = getGridElement().getFooterCell(0, 6);
assertEquals("6+7", mergedCell3.getText());
assertEquals("Colspan of cell [0,6]", "2", mergedCell3.getAttribute("colspan"));

}

private void toggleColumnHidable(int index) {
selectMenuPath("Component", "Columns", "Column " + index, "Hidable");
}
Expand Down

0 comments on commit 5eaac7a

Please sign in to comment.