Change-Id: I2a16ffbd59bf4863eb6a7bea8d4b590a693af637tags/7.4.4
@@ -2178,14 +2178,33 @@ public class Grid<T> extends ResizeComposite implements | |||
public final class SelectionColumn extends Column<Boolean, T> { | |||
private boolean initDone = false; | |||
private boolean selected = false; | |||
SelectionColumn(final Renderer<Boolean> selectColumnRenderer) { | |||
super(selectColumnRenderer); | |||
} | |||
void initDone() { | |||
addSelectAllToDefaultHeader(); | |||
setWidth(-1); | |||
setEditable(false); | |||
initDone = true; | |||
} | |||
protected void addSelectAllToDefaultHeader() { | |||
if (getSelectionModel() instanceof SelectionModel.Multi | |||
&& header.getDefaultRow() != null) { | |||
// If selection cell already contains a widget do not | |||
// create a new CheckBox | |||
HeaderCell selectionCell = header.getDefaultRow().getCell(this); | |||
if (selectionCell.getType() | |||
.equals(GridStaticCellType.WIDGET) | |||
&& selectionCell.getWidget() instanceof CheckBox) { | |||
return; | |||
} | |||
/* | |||
* TODO: Currently the select all check box is shown when multi | |||
* selection is in use. This might result in malfunctions if no | |||
@@ -2202,19 +2221,18 @@ public class Grid<T> extends ResizeComposite implements | |||
public void onValueChange(ValueChangeEvent<Boolean> event) { | |||
if (event.getValue()) { | |||
fireEvent(new SelectAllEvent<T>(model)); | |||
selected = true; | |||
} else { | |||
model.deselectAll(); | |||
selected = false; | |||
} | |||
} | |||
}); | |||
header.getDefaultRow().getCell(this).setWidget(checkBox); | |||
} | |||
checkBox.setValue(selected); | |||
setWidth(-1); | |||
setEditable(false); | |||
selectionCell.setWidget(checkBox); | |||
initDone = true; | |||
} | |||
} | |||
@Override | |||
@@ -3685,27 +3703,34 @@ public class Grid<T> extends ResizeComposite implements | |||
final StaticSection.StaticCell metadata = staticRow | |||
.getCell(columns.get(cell.getColumn())); | |||
boolean updateCellData = true; | |||
// Decorate default row with sorting indicators | |||
if (staticRow instanceof HeaderRow) { | |||
addSortingIndicatorsToHeaderRow((HeaderRow) staticRow, cell); | |||
if (isHeaderSelectionColumn(row, cell)) { | |||
updateCellData = false; | |||
} | |||
} | |||
// Assign colspan to cell before rendering | |||
cell.setColSpan(metadata.getColspan()); | |||
TableCellElement element = cell.getElement(); | |||
switch (metadata.getType()) { | |||
case TEXT: | |||
element.setInnerText(metadata.getText()); | |||
break; | |||
case HTML: | |||
element.setInnerHTML(metadata.getHtml()); | |||
break; | |||
case WIDGET: | |||
preDetach(row, Arrays.asList(cell)); | |||
element.setInnerHTML(""); | |||
postAttach(row, Arrays.asList(cell)); | |||
break; | |||
if (updateCellData) { | |||
switch (metadata.getType()) { | |||
case TEXT: | |||
element.setInnerText(metadata.getText()); | |||
break; | |||
case HTML: | |||
element.setInnerHTML(metadata.getHtml()); | |||
break; | |||
case WIDGET: | |||
preDetach(row, Arrays.asList(cell)); | |||
element.setInnerHTML(""); | |||
postAttach(row, Arrays.asList(cell)); | |||
break; | |||
} | |||
} | |||
setCustomStyleName(element, metadata.getStyleName()); | |||
@@ -3765,6 +3790,27 @@ public class Grid<T> extends ResizeComposite implements | |||
@Override | |||
public void preAttach(Row row, Iterable<FlyweightCell> cellsToAttach) { | |||
// Add select all checkbox if needed on rebuild. | |||
for (FlyweightCell cell : cellsToAttach) { | |||
if (isHeaderSelectionColumn(row, cell)) { | |||
selectionColumn.addSelectAllToDefaultHeader(); | |||
} | |||
} | |||
} | |||
/** | |||
* Check if selectionColumn in the default header row | |||
*/ | |||
private boolean isHeaderSelectionColumn(Row row, FlyweightCell cell) { | |||
return selectionColumn != null && isDefaultHeaderRow(row) | |||
&& getColumn(cell.getColumn()).equals(selectionColumn); | |||
} | |||
/** | |||
* Row is the default header row. | |||
*/ | |||
private boolean isDefaultHeaderRow(Row row) { | |||
return section.getRow(row.getRow()).equals(header.getDefaultRow()); | |||
} | |||
@Override |
@@ -0,0 +1,183 @@ | |||
/* | |||
* 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; | |||
import java.io.Serializable; | |||
import com.vaadin.data.util.BeanItemContainer; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.tests.components.AbstractTestUI; | |||
import com.vaadin.ui.Button; | |||
import com.vaadin.ui.Button.ClickEvent; | |||
import com.vaadin.ui.Grid; | |||
import com.vaadin.ui.Grid.HeaderRow; | |||
import com.vaadin.ui.Grid.SelectionMode; | |||
import com.vaadin.ui.Grid.SelectionModel; | |||
import com.vaadin.ui.HorizontalLayout; | |||
import com.vaadin.ui.renderers.NumberRenderer; | |||
public class GridHeaderFormatChange extends AbstractTestUI { | |||
private static final long serialVersionUID = -2787771187365766027L; | |||
private HeaderRow row; | |||
public class Person implements Serializable { | |||
private static final long serialVersionUID = -7995927620756317000L; | |||
String firstName; | |||
String lastName; | |||
String streetAddress; | |||
Integer zipCode; | |||
String city; | |||
public Person(String firstName, String lastName, String streetAddress, | |||
Integer zipCode, String city) { | |||
this.firstName = firstName; | |||
this.lastName = lastName; | |||
this.streetAddress = streetAddress; | |||
this.zipCode = zipCode; | |||
this.city = city; | |||
} | |||
public String getFirstName() { | |||
return firstName; | |||
} | |||
public void setFirstName(String firstName) { | |||
this.firstName = firstName; | |||
} | |||
public String getLastName() { | |||
return lastName; | |||
} | |||
public void setLastName(String lastName) { | |||
this.lastName = lastName; | |||
} | |||
public String getStreetAddress() { | |||
return streetAddress; | |||
} | |||
public void setStreetAddress(String streetAddress) { | |||
this.streetAddress = streetAddress; | |||
} | |||
public Integer getZipCode() { | |||
return zipCode; | |||
} | |||
public void setZipCode(Integer zipCode) { | |||
this.zipCode = zipCode; | |||
} | |||
public String getCity() { | |||
return city; | |||
} | |||
public void setCity(String city) { | |||
this.city = city; | |||
} | |||
} | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
BeanItemContainer<Person> datasource = new BeanItemContainer<Person>( | |||
Person.class); | |||
final Grid grid; | |||
datasource.addItem(new Person("Rudolph", "Reindeer", "Ruukinkatu 2-4", | |||
20540, "Turku")); | |||
grid = new Grid(datasource); | |||
grid.setWidth("600px"); | |||
grid.getColumn("zipCode").setRenderer(new NumberRenderer()); | |||
grid.setColumnOrder("firstName", "lastName", "streetAddress", | |||
"zipCode", "city"); | |||
grid.setSelectionMode(SelectionMode.SINGLE); | |||
addComponent(grid); | |||
Button showHide = new Button("Hide firstName", | |||
new Button.ClickListener() { | |||
private static final long serialVersionUID = 8107530972693788705L; | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
if (grid.getColumn("firstName") != null) { | |||
grid.removeColumn("firstName"); | |||
event.getButton().setCaption("Show firstName"); | |||
} else { | |||
grid.addColumn("firstName"); | |||
grid.setColumnOrder("firstName", "lastName", | |||
"streetAddress", "zipCode", "city"); | |||
event.getButton().setCaption("Hide firstName"); | |||
} | |||
} | |||
}); | |||
showHide.setId("show_hide"); | |||
Button selectionMode = new Button("Set multiselect", | |||
new Button.ClickListener() { | |||
private static final long serialVersionUID = 8107530972693788705L; | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
if (grid.getSelectionModel() instanceof SelectionModel.Single) { | |||
grid.setSelectionMode(SelectionMode.MULTI); | |||
} else { | |||
grid.setSelectionMode(SelectionMode.SINGLE); | |||
} | |||
} | |||
}); | |||
selectionMode.setId("selection_mode"); | |||
Button join = new Button("Add Join header column", | |||
new Button.ClickListener() { | |||
private static final long serialVersionUID = -5330801275551280623L; | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
if (row == null) { | |||
row = grid.prependHeaderRow(); | |||
if (grid.getColumn("firstName") != null) { | |||
row.join("firstName", "lastName").setText( | |||
"Full Name"); | |||
} | |||
row.join("streetAddress", "zipCode", "city") | |||
.setText("Address"); | |||
} else { | |||
grid.removeHeaderRow(row); | |||
row = null; | |||
} | |||
} | |||
}); | |||
join.setId("join"); | |||
addComponent(new HorizontalLayout(showHide, selectionMode, join)); | |||
} | |||
@Override | |||
protected String getTestDescription() { | |||
return "Grid for testing header re-rendering."; | |||
} | |||
@Override | |||
protected Integer getTicketNumber() { | |||
return 17131; | |||
} | |||
} |
@@ -0,0 +1,156 @@ | |||
/* | |||
* 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; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import org.openqa.selenium.By; | |||
import com.vaadin.testbench.elements.ButtonElement; | |||
import com.vaadin.testbench.elements.GridElement; | |||
import com.vaadin.testbench.parallel.TestCategory; | |||
import com.vaadin.tests.tb3.MultiBrowserTest; | |||
@TestCategory("grid") | |||
public class GridHeaderFormatChangeTest extends MultiBrowserTest { | |||
@Test | |||
public void testHeaderRetainsSelectAllForColumnRemoval() { | |||
openTestURL(); | |||
GridElement grid = $(GridElement.class).first(); | |||
// Assert that we do not have the select all checkbox | |||
Assert.assertTrue( | |||
"Found input in header even though none should exist.", grid | |||
.getHeader().findElements(By.tagName("input")) | |||
.isEmpty()); | |||
// Set grid into multiselection mode | |||
toggleSelectionMode(); | |||
// Assert that we now have a select all checkbox in the header | |||
Assert.assertFalse("Expected one input field in header", grid | |||
.getHeader().findElements(By.tagName("input")).isEmpty()); | |||
// Hide the firstName column from the grid. | |||
toggleFirstName(); | |||
// Assert that we still have the select all checkbox in the header. | |||
Assert.assertFalse("Header was missing checkbox after hiding column", | |||
grid.getHeader().findElements(By.tagName("input")).isEmpty()); | |||
// Show the firstName column. | |||
toggleFirstName(); | |||
// Assert that we still have the select all checkbox in the header. | |||
Assert.assertFalse( | |||
"Header was missing checkbox after bringing back column", grid | |||
.getHeader().findElements(By.tagName("input")) | |||
.isEmpty()); | |||
} | |||
@Test | |||
public void testHeaderRetainsSelectAllForJoinColumnAdd() { | |||
openTestURL(); | |||
GridElement grid = $(GridElement.class).first(); | |||
// Assert that we do not have the select all checkbox | |||
Assert.assertTrue( | |||
"Found input in header even though none should exist.", grid | |||
.getHeader().findElements(By.tagName("input")) | |||
.isEmpty()); | |||
// Set grid into multiselection mode | |||
toggleSelectionMode(); | |||
// Assert that we now have a select all checkbox in the header | |||
Assert.assertFalse("Expected one input field in header", grid | |||
.getHeader().findElements(By.tagName("input")).isEmpty()); | |||
// Add Join columns header | |||
toggleJoin(); | |||
// Assert that we still have the select all checkbox in the header. | |||
Assert.assertFalse("Header was missing checkbox after hiding column", | |||
grid.getHeader().findElements(By.tagName("input")).isEmpty()); | |||
// remove Join Columns header | |||
toggleJoin(); | |||
// Assert that we still have the select all checkbox in the header. | |||
Assert.assertFalse( | |||
"Header was missing checkbox after bringing back column", grid | |||
.getHeader().findElements(By.tagName("input")) | |||
.isEmpty()); | |||
} | |||
@Test | |||
public void selectAllShouldKeepState() { | |||
openTestURL(); | |||
GridElement grid = $(GridElement.class).first(); | |||
// Assert that we do not have the select all checkbox | |||
Assert.assertTrue( | |||
"Found input in header even though none should exist.", grid | |||
.getHeader().findElements(By.tagName("input")) | |||
.isEmpty()); | |||
// Set grid into multiselection mode | |||
toggleSelectionMode(); | |||
// Assert that we now have a select all checkbox in the header | |||
Assert.assertFalse("Should not be selected after adding", grid | |||
.getHeader().findElement(By.tagName("input")).isSelected()); | |||
grid.getHeader().findElement(By.tagName("input")).click(); | |||
// Assert that checkbox is checked | |||
assertSelectAllChecked( | |||
"Not selected even though we just clicked selection", grid); | |||
// Hide the firstName column from the grid. | |||
toggleFirstName(); | |||
// Assert that checkbox is still checked | |||
assertSelectAllChecked("Selection disappeared after removing column", | |||
grid); | |||
// Show the firstName column. | |||
toggleFirstName(); | |||
// Assert that checkbox is still checked | |||
assertSelectAllChecked("Selection disappeared after adding column", | |||
grid); | |||
} | |||
private void assertSelectAllChecked(String message, GridElement grid) { | |||
Assert.assertTrue(message, | |||
grid.getHeader().findElement(By.tagName("input")).isSelected()); | |||
} | |||
private void toggleSelectionMode() { | |||
$(ButtonElement.class).id("selection_mode").click(); | |||
} | |||
private void toggleFirstName() { | |||
$(ButtonElement.class).id("show_hide").click(); | |||
} | |||
private void toggleJoin() { | |||
$(ButtonElement.class).id("join").click(); | |||
} | |||
} |