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;
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;
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;
/* 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;
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() {
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);
.containsValue(id) : "Column with given id already exists.";
getWidget().addColumn(column);
columnToIdMap.put(column, id);
+ idToColumn.put(id, column);
}
/**
assert columnToIdMap
.containsKey(column) : "Given Column does not exist.";
getWidget().removeColumn(column);
- columnToIdMap.remove(column);
+ String id = columnToIdMap.remove(column);
+ idToColumn.remove(id);
}
@Override
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;
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)));
}
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.
*
}
}
+ /**
+ * 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<>();
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()) {
* the value provider
* @param renderer
* the column value class
- * @param <T>
- * the type of this grid
* @param <V>
* the column value type
*
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;
}
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.
*
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
primaryStyleName = "v-grid";
}
+ /** The state of the header section. */
+ public SectionState header = new SectionState();
+
/**
* Column order in grid.
*/
--- /dev/null
+/*
+ * 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<>();
+}
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;
import com.vaadin.ui.TextField;
import com.vaadin.ui.renderers.NumberRenderer;
+@Widgetset("com.vaadin.DefaultWidgetSet")
public class GridColumnResizing extends AbstractTestUI {
@Override
@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";
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()));
createSizeMenu(componentMenu.addItem("Size", null));
createDetailsMenu(componentMenu.addItem("Details", null));
createBodyMenu(componentMenu.addItem("Body rows", null));
+ createHeaderMenu(componentMenu.addItem("Header", null));
return menu;
}
});
}
+ 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) {
--- /dev/null
+/*
+ * 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);
+ }
+}