diff options
10 files changed, 296 insertions, 12 deletions
diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index 9fc4b65349..556a5ad7aa 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -50,6 +50,8 @@ import com.vaadin.client.ui.grid.Grid.HeaderCell; import com.vaadin.client.ui.grid.Grid.HeaderRow; import com.vaadin.client.ui.grid.GridColumn; import com.vaadin.client.ui.grid.Renderer; +import com.vaadin.client.ui.grid.events.SelectAllEvent; +import com.vaadin.client.ui.grid.events.SelectAllHandler; import com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel; import com.vaadin.client.ui.grid.selection.SelectionChangeEvent; import com.vaadin.client.ui.grid.selection.SelectionChangeHandler; @@ -402,6 +404,15 @@ public class GridConnector extends AbstractHasComponentsConnector implements } }); + getWidget().addSelectAllHandler(new SelectAllHandler<JSONObject>() { + + @Override + public void onSelectAll(SelectAllEvent<JSONObject> event) { + getRpcProxy(GridServerRpc.class).selectAll(); + } + + }); + getWidget().getEditorRow().setHandler(new CustomEditorRowHandler()); getLayoutManager().registerDependency(this, getWidget().getElement()); layout(); diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index 8e883a3917..ddd020a0e1 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -38,11 +38,14 @@ import com.google.gwt.dom.client.TableRowElement; import com.google.gwt.dom.client.Touch; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyEvent; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.touch.client.Point; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.ResizeComposite; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.DeferredWorker; @@ -66,12 +69,15 @@ import com.vaadin.client.ui.grid.events.HeaderKeyPressHandler; import com.vaadin.client.ui.grid.events.HeaderKeyUpHandler; import com.vaadin.client.ui.grid.events.ScrollEvent; import com.vaadin.client.ui.grid.events.ScrollHandler; +import com.vaadin.client.ui.grid.events.SelectAllEvent; +import com.vaadin.client.ui.grid.events.SelectAllHandler; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.WidgetRenderer; import com.vaadin.client.ui.grid.selection.HasSelectionChangeHandlers; import com.vaadin.client.ui.grid.selection.SelectionChangeEvent; import com.vaadin.client.ui.grid.selection.SelectionChangeHandler; import com.vaadin.client.ui.grid.selection.SelectionModel; +import com.vaadin.client.ui.grid.selection.SelectionModel.Multi; import com.vaadin.client.ui.grid.selection.SelectionModelMulti; import com.vaadin.client.ui.grid.selection.SelectionModelNone; import com.vaadin.client.ui.grid.selection.SelectionModelSingle; @@ -1372,6 +1378,31 @@ public class Grid<T> extends ResizeComposite implements } void initDone() { + if (getSelectionModel() instanceof SelectionModel.Multi + && header.getDefaultRow() != null) { + /* + * TODO: Currently the select all check box is shown when multi + * selection is in use. This might result in malfunctions if no + * SelectAllHandlers are present. + * + * Later on this could be fixed so that it check such handlers + * exist. + */ + final SelectionModel.Multi<T> model = (Multi<T>) getSelectionModel(); + final CheckBox checkBox = new CheckBox(); + checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() { + + @Override + public void onValueChange(ValueChangeEvent<Boolean> event) { + if (event.getValue()) { + fireEvent(new SelectAllEvent<T>(model)); + } else { + model.deselectAll(); + } + } + }); + header.getDefaultRow().getCell(this).setWidget(checkBox); + } initDone = true; } @@ -3042,7 +3073,6 @@ public class Grid<T> extends ResizeComposite implements if (size > 0) { escalator.getBody().insertRows(0, size); } - } /** @@ -4001,6 +4031,17 @@ public class Grid<T> extends ResizeComposite implements } /** + * Register a GWT event handler for a select all event. This handler gets + * called whenever Grid needs all rows selected. + * + * @param handler + * a select all event handler + */ + public HandlerRegistration addSelectAllHandler(SelectAllHandler<T> handler) { + return addHandler(handler, SelectAllEvent.getType()); + } + + /** * Register a GWT event handler for a data available event. This handler * gets called whenever the {@link DataSource} for this Grid has new data * available. diff --git a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java index 9dfaa0f439..04617b05f0 100644 --- a/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java +++ b/client/src/com/vaadin/client/ui/grid/datasources/ListDataSource.java @@ -26,6 +26,8 @@ import java.util.ListIterator; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; +import com.vaadin.client.ui.grid.events.SelectAllEvent; +import com.vaadin.client.ui.grid.events.SelectAllHandler; import com.vaadin.shared.util.SharedUtil; /** @@ -445,4 +447,18 @@ public class ListDataSource<T> implements DataSource<T> { public int indexOf(T row) { return ds.indexOf(row); } + + /** + * Returns a {@link SelectAllHandler} for this ListDataSource. + * + * @return select all handler + */ + public SelectAllHandler<T> getSelectAllHandler() { + return new SelectAllHandler<T>() { + @Override + public void onSelectAll(SelectAllEvent<T> event) { + event.getSelectionModel().select(asList()); + } + }; + } } diff --git a/client/src/com/vaadin/client/ui/grid/events/SelectAllEvent.java b/client/src/com/vaadin/client/ui/grid/events/SelectAllEvent.java new file mode 100644 index 0000000000..0fb32478ea --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/SelectAllEvent.java @@ -0,0 +1,59 @@ +/* + * 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.client.ui.grid.events; + +import com.google.gwt.event.shared.GwtEvent; +import com.vaadin.client.ui.grid.selection.SelectionModel; + +/** + * A select all event, fired by the Grid when it needs all rows in data source + * to be selected. + * + * @since + * @author Vaadin Ltd + */ +public class SelectAllEvent<T> extends GwtEvent<SelectAllHandler<T>> { + + /** + * Handler type. + */ + private final static Type<SelectAllHandler<?>> TYPE = new Type<SelectAllHandler<?>>();; + + private SelectionModel.Multi<T> selectionModel; + + public SelectAllEvent(SelectionModel.Multi<T> selectionModel) { + this.selectionModel = selectionModel; + } + + public static final Type<SelectAllHandler<?>> getType() { + return TYPE; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public Type<SelectAllHandler<T>> getAssociatedType() { + return (Type) TYPE; + } + + @Override + protected void dispatch(SelectAllHandler<T> handler) { + handler.onSelectAll(this); + } + + public SelectionModel.Multi<T> getSelectionModel() { + return selectionModel; + } +} diff --git a/client/src/com/vaadin/client/ui/grid/events/SelectAllHandler.java b/client/src/com/vaadin/client/ui/grid/events/SelectAllHandler.java new file mode 100644 index 0000000000..b93eedf315 --- /dev/null +++ b/client/src/com/vaadin/client/ui/grid/events/SelectAllHandler.java @@ -0,0 +1,37 @@ +/* + * 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.client.ui.grid.events; + +import com.google.gwt.event.shared.EventHandler; + +/** + * Handler for a Grid select all event, called when the Grid needs all rows in + * data source to be selected. + * + * @since + * @author Vaadin Ltd + */ +public interface SelectAllHandler<T> extends EventHandler { + + /** + * Called when select all value in SelectionColumn header changes value. + * + * @param event + * select all event telling that all rows should be selected + */ + public void onSelectAll(SelectAllEvent<T> event); + +} diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index aff0fe0e8a..f12a774004 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -2105,6 +2105,13 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier, setSortOrder(order, originator); } + + @Override + public void selectAll() { + assert getSelectionModel() instanceof SelectionModel.Multi : "Not a multi selection model!"; + + ((SelectionModel.Multi) getSelectionModel()).selectAll(); + } }); registerRpc(new EditorRowServerRpc() { diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java index fd671e30a7..c87e2a813f 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java @@ -30,4 +30,6 @@ public interface GridServerRpc extends ServerRpc { void sort(String[] columnIds, SortDirection[] directions, SortEventOriginator originator); + + void selectAll(); } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java index 4b47837887..08bb495f2c 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java @@ -15,11 +15,15 @@ */ package com.vaadin.tests.components.grid.basicfeatures.client; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; +import com.vaadin.testbench.By; +import com.vaadin.tests.components.grid.GridElement.GridCellElement; import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest; +import com.vaadin.tests.widgetset.client.grid.GridBasicClientFeaturesWidget; public class GridClientSelectionTest extends GridBasicClientFeaturesTest { @@ -27,11 +31,72 @@ public class GridClientSelectionTest extends GridBasicClientFeaturesTest { public void testChangeSelectionMode() { openTestURL(); - selectMenuPath("Component", "State", "Selection mode", "none"); + setSelectionModelNone(); assertTrue("First column was selection column", getGridElement() .getCell(0, 0).getText().equals("(0, 0)")); - selectMenuPath("Component", "State", "Selection mode", "multi"); + setSelectionModelMulti(); assertTrue("First column was not selection column", getGridElement() .getCell(0, 1).getText().equals("(0, 0)")); } + + @Test + public void testSelectAllCheckbox() { + openTestURL(); + + setSelectionModelMulti(); + GridCellElement header = getGridElement().getHeaderCell(0, 0); + + assertTrue("No checkbox", header.isElementPresent(By.tagName("input"))); + header.findElement(By.tagName("input")).click(); + + for (int i = 0; i < GridBasicClientFeaturesWidget.ROWS; i += 100) { + assertTrue("Row " + i + " was not selected.", getGridElement() + .getRow(i).isSelected()); + } + + header.findElement(By.tagName("input")).click(); + assertFalse("Row 100 was still selected", getGridElement().getRow(100) + .isSelected()); + } + + @Test + public void testSelectAllCheckboxWhenChangingModels() { + openTestURL(); + + GridCellElement header; + header = getGridElement().getHeaderCell(0, 0); + assertFalse( + "Check box shouldn't have been in header for None Selection Model", + header.isElementPresent(By.tagName("input"))); + + setSelectionModelMulti(); + header = getGridElement().getHeaderCell(0, 0); + assertTrue("Multi Selection Model should have select all checkbox", + header.isElementPresent(By.tagName("input"))); + + setSelectionModelSingle(); + header = getGridElement().getHeaderCell(0, 0); + assertFalse( + "Check box shouldn't have been in header for Single Selection Model", + header.isElementPresent(By.tagName("input"))); + + setSelectionModelNone(); + header = getGridElement().getHeaderCell(0, 0); + assertFalse( + "Check box shouldn't have been in header for None Selection Model", + header.isElementPresent(By.tagName("input"))); + + } + + private void setSelectionModelMulti() { + selectMenuPath("Component", "State", "Selection mode", "multi"); + } + + private void setSelectionModelSingle() { + selectMenuPath("Component", "State", "Selection mode", "single"); + } + + private void setSelectionModelNone() { + selectMenuPath("Component", "State", "Selection mode", "none"); + } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java index 6e2ac91df2..9a1890eaf0 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java @@ -22,9 +22,11 @@ import org.junit.Test; import org.openqa.selenium.Keys; import org.openqa.selenium.interactions.Actions; -import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.By; import com.vaadin.tests.components.grid.GridElement; +import com.vaadin.tests.components.grid.GridElement.GridCellElement; import com.vaadin.tests.components.grid.GridElement.GridRowElement; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures; import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; public class GridSelectionTest extends GridBasicFeaturesTest { @@ -151,6 +153,55 @@ public class GridSelectionTest extends GridBasicFeaturesTest { } + @Test + public void testSelectAllCheckbox() { + openTestURL(); + + setSelectionModelMulti(); + GridCellElement header = getGridElement().getHeaderCell(0, 0); + + assertTrue("No checkbox", header.isElementPresent(By.tagName("input"))); + header.findElement(By.tagName("input")).click(); + + for (int i = 0; i < GridBasicFeatures.ROWS; i += 100) { + assertTrue("Row " + i + " was not selected.", getGridElement() + .getRow(i).isSelected()); + } + + header.findElement(By.tagName("input")).click(); + assertFalse("Row 100 was still selected", getGridElement().getRow(100) + .isSelected()); + } + + @Test + public void testSelectAllCheckboxWhenChangingModels() { + openTestURL(); + + GridCellElement header; + header = getGridElement().getHeaderCell(0, 0); + assertFalse( + "Check box shouldn't have been in header for None Selection Model", + header.isElementPresent(By.tagName("input"))); + + setSelectionModelMulti(); + header = getGridElement().getHeaderCell(0, 0); + assertTrue("Multi Selection Model should have select all checkbox", + header.isElementPresent(By.tagName("input"))); + + setSelectionModelSingle(); + header = getGridElement().getHeaderCell(0, 0); + assertFalse( + "Check box shouldn't have been in header for Single Selection Model", + header.isElementPresent(By.tagName("input"))); + + setSelectionModelNone(); + header = getGridElement().getHeaderCell(0, 0); + assertFalse( + "Check box shouldn't have been in header for None Selection Model", + header.isElementPresent(By.tagName("input"))); + + } + private void setSelectionModelMulti() { selectMenuPath("Component", "State", "Selection mode", "multi"); } @@ -159,14 +210,8 @@ public class GridSelectionTest extends GridBasicFeaturesTest { selectMenuPath("Component", "State", "Selection mode", "single"); } - @SuppressWarnings("static-method") - private boolean isSelected(TestBenchElement row) { - /* - * FIXME We probably should get a GridRow instead of a plain - * TestBenchElement, that has an "isSelected" thing integrated. (henrik - * paul 26.6.2014) - */ - return row.getAttribute("class").contains("-row-selected"); + private void setSelectionModelNone() { + selectMenuPath("Component", "State", "Selection mode", "none"); } private void toggleFirstRowSelection() { diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index b89f87f3cd..a6bc3863a5 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -238,6 +238,7 @@ public class GridBasicClientFeaturesWidget extends grid = getTestedWidget(); grid.getElement().setId("testComponent"); grid.setDataSource(ds); + grid.addSelectAllHandler(ds.getSelectAllHandler()); grid.setSelectionMode(SelectionMode.NONE); grid.getEditorRow().setHandler(new TestEditorRowHandler()); |