Browse Source

Add API for controlling deselection for single select model (#16567)

Change-Id: Ieb245205b3a311a4563f39bc48baadc44e218b61
tags/7.4.0.rc1
Leif Åstrand 9 years ago
parent
commit
fa5f781429

+ 14
- 0
client/src/com/vaadin/client/connectors/GridConnector.java View File

@@ -57,6 +57,7 @@ import com.vaadin.client.widget.grid.events.SelectAllHandler;
import com.vaadin.client.widget.grid.selection.AbstractRowHandleSelectionModel;
import com.vaadin.client.widget.grid.selection.SelectionEvent;
import com.vaadin.client.widget.grid.selection.SelectionHandler;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.client.widget.grid.selection.SelectionModelMulti;
import com.vaadin.client.widget.grid.selection.SelectionModelNone;
import com.vaadin.client.widget.grid.selection.SelectionModelSingle;
@@ -536,7 +537,12 @@ public class GridConnector extends AbstractHasComponentsConnector implements
// Selection
if (stateChangeEvent.hasPropertyChanged("selectionMode")) {
onSelectionModeChange();
updateSelectDeselectAllowed();
} else if (stateChangeEvent
.hasPropertyChanged("singleSelectDeselectAllowed")) {
updateSelectDeselectAllowed();
}

if (stateChangeEvent.hasPropertyChanged("selectedKeys")) {
updateSelectionFromState();
}
@@ -567,6 +573,14 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
}

private void updateSelectDeselectAllowed() {
SelectionModel<JsonObject> model = getWidget().getSelectionModel();
if (model instanceof SelectionModel.Single<?>) {
((SelectionModel.Single<?>) model)
.setDeselectAllowed(getState().singleSelectDeselectAllowed);
}
}

private void updateColumnOrderFromState(List<String> stateColumnOrder) {
CustomGridColumn[] columns = new CustomGridColumn[stateColumnOrder
.size()];

+ 14
- 0
client/src/com/vaadin/client/widget/grid/selection/ClickSelectHandler.java View File

@@ -30,6 +30,7 @@ public class ClickSelectHandler<T> {

private Grid<T> grid;
private HandlerRegistration clickHandler;
private boolean deselectAllowed = true;

private class RowClickHandler implements BodyClickHandler {

@@ -38,6 +39,8 @@ public class ClickSelectHandler<T> {
T row = (T) event.getTargetCell().getRow();
if (!grid.isSelected(row)) {
grid.select(row);
} else if (deselectAllowed) {
grid.deselect(row);
}
}
}
@@ -60,4 +63,15 @@ public class ClickSelectHandler<T> {
public void removeHandler() {
clickHandler.removeHandler();
}

/**
* Sets whether clicking the currently selected row should deselect the row.
*
* @param deselectAllowed
* <code>true</code> to allow deselecting the selected row;
* otherwise <code>false</code>
*/
public void setDeselectAllowed(boolean deselectAllowed) {
this.deselectAllowed = deselectAllowed;
}
}

+ 20
- 0
client/src/com/vaadin/client/widget/grid/selection/SelectionModel.java View File

@@ -116,6 +116,26 @@ public interface SelectionModel<T> {
*/
public T getSelectedRow();

/**
* Sets whether it's allowed to deselect the selected row through the
* UI. Deselection is allowed by default.
*
* @param deselectAllowed
* <code>true</code> if the selected row can be deselected
* without selecting another row instead; otherwise
* <code>false</code>.
*/
public void setDeselectAllowed(boolean deselectAllowed);

/**
* Sets whether it's allowed to deselect the selected row through the
* UI.
*
* @return <code>true</code> if deselection is allowed; otherwise
* <code>false</code>
*/
public boolean isDeselectAllowed();

}

/**

+ 24
- 0
client/src/com/vaadin/client/widget/grid/selection/SelectionModelSingle.java View File

@@ -40,6 +40,8 @@ public class SelectionModelSingle<T> extends AbstractRowHandleSelectionModel<T>
/** Event handling for selection by clicking cells */
private ClickSelectHandler<T> clickSelectHandler;

private boolean deselectAllowed = true;

@Override
public boolean isSelected(T row) {
return selectedRow != null
@@ -66,6 +68,7 @@ public class SelectionModelSingle<T> extends AbstractRowHandleSelectionModel<T>
if (this.grid != null) {
spaceSelectHandler = new SpaceSelectHandler<T>(grid);
clickSelectHandler = new ClickSelectHandler<T>(grid);
updateHandlerDeselectAllowed();
} else {
spaceSelectHandler.removeHandler();
clickSelectHandler.removeHandler();
@@ -148,4 +151,25 @@ public class SelectionModelSingle<T> extends AbstractRowHandleSelectionModel<T>
return false;
}
}

@Override
public void setDeselectAllowed(boolean deselectAllowed) {
this.deselectAllowed = deselectAllowed;
updateHandlerDeselectAllowed();
}

@Override
public boolean isDeselectAllowed() {
return deselectAllowed;
}

private void updateHandlerDeselectAllowed() {
if (spaceSelectHandler != null) {
spaceSelectHandler.setDeselectAllowed(deselectAllowed);
}
if (clickSelectHandler != null) {
clickSelectHandler.setDeselectAllowed(deselectAllowed);
}
}

}

+ 16
- 3
client/src/com/vaadin/client/widget/grid/selection/SpaceSelectHandler.java View File

@@ -79,10 +79,10 @@ public class SpaceSelectHandler<T> {
protected void setSelected(Grid<T> grid, int rowIndex) {
T row = grid.getDataSource().getRow(rowIndex);

if (grid.isSelected(row)) {
grid.deselect(row);
} else {
if (!grid.isSelected(row)) {
grid.select(row);
} else if (deselectAllowed) {
grid.deselect(row);
}
}
}
@@ -91,6 +91,7 @@ public class SpaceSelectHandler<T> {
private Grid<T> grid;
private HandlerRegistration spaceUpHandler;
private HandlerRegistration spaceDownHandler;
private boolean deselectAllowed = true;

/**
* Constructor for SpaceSelectHandler. This constructor will add all
@@ -121,4 +122,16 @@ public class SpaceSelectHandler<T> {
spaceDownHandler.removeHandler();
spaceUpHandler.removeHandler();
}

/**
* Sets whether pressing space for the currently selected row should
* deselect the row.
*
* @param deselectAllowed
* <code>true</code> to allow deselecting the selected row;
* otherwise <code>false</code>
*/
public void setDeselectAllowed(boolean deselectAllowed) {
this.deselectAllowed = deselectAllowed;
}
}

+ 30
- 0
server/src/com/vaadin/ui/Grid.java View File

@@ -642,6 +642,26 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* <code>null</code> if nothing is selected
*/
Object getSelectedRow();

/**
* Sets whether it's allowed to deselect the selected row through
* the UI. Deselection is allowed by default.
*
* @param deselectAllowed
* <code>true</code> if the selected row can be
* deselected without selecting another row instead;
* otherwise <code>false</code>.
*/
public void setDeselectAllowed(boolean deselectAllowed);

/**
* Sets whether it's allowed to deselect the selected row through
* the UI.
*
* @return <code>true</code> if deselection is allowed; otherwise
* <code>false</code>
*/
public boolean isDeselectAllowed();
}

/**
@@ -815,6 +835,16 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
public void reset() {
deselect(getSelectedRow());
}

@Override
public void setDeselectAllowed(boolean deselectAllowed) {
grid.getState().singleSelectDeselectAllowed = deselectAllowed;
}

@Override
public boolean isDeselectAllowed() {
return grid.getState(false).singleSelectDeselectAllowed;
}
}

/**

+ 3
- 0
shared/src/com/vaadin/shared/ui/grid/GridState.java View File

@@ -132,6 +132,9 @@ public class GridState extends AbstractComponentState {

public SharedSelectionMode selectionMode;

/** Whether single select mode can be cleared through the UI */
public boolean singleSelectDeselectAllowed = true;

/** Keys of the currently sorted columns */
public String[] sortColumns = new String[0];


+ 20
- 0
uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java View File

@@ -57,6 +57,7 @@ import com.vaadin.ui.Grid.MultiSelectionModel;
import com.vaadin.ui.Grid.RowReference;
import com.vaadin.ui.Grid.RowStyleGenerator;
import com.vaadin.ui.Grid.SelectionMode;
import com.vaadin.ui.Grid.SelectionModel;
import com.vaadin.ui.renderer.DateRenderer;
import com.vaadin.ui.renderer.HtmlRenderer;
import com.vaadin.ui.renderer.NumberRenderer;
@@ -82,6 +83,8 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {

private int containerDelay = 0;

private boolean singleSelectAllowDeselect = true;

private IndexedContainer ds;
private Grid grid;
private SelectionListener selectionListener = new SelectionListener() {
@@ -320,6 +323,9 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
grid.setSelectionMode(selectionMode);
if (selectionMode == SelectionMode.SINGLE) {
grid.addSelectionListener(selectionListener);

((SelectionModel.Single) grid.getSelectionModel())
.setDeselectAllowed(singleSelectAllowDeselect);
} else {
grid.removeSelectionListener(selectionListener);
}
@@ -488,6 +494,20 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}

});

createBooleanAction("Single select allow deselect", "State",
singleSelectAllowDeselect, new Command<Grid, Boolean>() {
@Override
public void execute(Grid c, Boolean value, Object data) {
singleSelectAllowDeselect = value.booleanValue();

SelectionModel model = c.getSelectionModel();
if (model instanceof SelectionModel.Single) {
((SelectionModel.Single) model)
.setDeselectAllowed(singleSelectAllowDeselect);
}
}
});
}

protected void createHeaderActions() {

+ 125
- 5
uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientSelectionTest.java View File

@@ -19,6 +19,8 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;
import org.openqa.selenium.Keys;
import org.openqa.selenium.interactions.Actions;

import com.vaadin.testbench.By;
import com.vaadin.testbench.elements.GridElement.GridCellElement;
@@ -74,7 +76,7 @@ public class GridClientSelectionTest extends GridBasicClientFeaturesTest {
assertTrue("Multi Selection Model should have select all checkbox",
header.isElementPresent(By.tagName("input")));

setSelectionModelSingle();
setSelectionModelSingle(true);
header = getGridElement().getHeaderCell(0, 0);
assertFalse(
"Check box shouldn't have been in header for Single Selection Model",
@@ -88,15 +90,133 @@ public class GridClientSelectionTest extends GridBasicClientFeaturesTest {

}

@Test
public void testDeselectAllowedMouseInput() {
openTestURL();

setSelectionModelSingle(true);

getGridElement().getCell(5, 1).click();

assertTrue("Row 5 should be selected after clicking", isRowSelected(5));

getGridElement().getCell(7, 1).click();

assertFalse("Row 5 should be deselected after clicking another row",
isRowSelected(5));
assertTrue("Row 7 should be selected after clicking", isRowSelected(7));

getGridElement().getCell(7, 1).click();

assertFalse("Row should be deselected after clicking again",
isRowSelected(7));
}

@Test
public void testDeselectAllowedKeyboardInput() {
openTestURL();

setSelectionModelSingle(true);

getGridElement().getHeaderCell(0, 1).click();

new Actions(getDriver()).sendKeys(Keys.ARROW_DOWN).perform();

new Actions(getDriver()).sendKeys(Keys.SPACE).perform();

assertTrue("Row 0 should be selected after pressing space",
isRowSelected(0));

new Actions(getDriver()).sendKeys(Keys.ARROW_DOWN).perform();

new Actions(getDriver()).sendKeys(Keys.SPACE).perform();

assertFalse(
"Row 0 should be deselected after pressing space another row",
isRowSelected(0));
assertTrue("Row 1 should be selected after pressing space",
isRowSelected(1));

new Actions(getDriver()).sendKeys(Keys.SPACE).perform();

assertFalse("Row should be deselected after pressing space again",
isRowSelected(1));
}

@Test
public void testDeselectNotAllowedMouseInput() {
openTestURL();

setSelectionModelSingle(false);

getGridElement().getCell(5, 1).click();

assertTrue("Row 5 should be selected after clicking", isRowSelected(5));

getGridElement().getCell(7, 1).click();

assertFalse("Row 5 should be deselected after clicking another row",
isRowSelected(5));
assertTrue("Row 7 should be selected after clicking", isRowSelected(7));

getGridElement().getCell(7, 1).click();

assertTrue("Row should remain selected after clicking again",
isRowSelected(7));
}

@Test
public void testDeselectNotAllowedKeyboardInput() {
openTestURL();

setSelectionModelSingle(false);

getGridElement().getHeaderCell(0, 1).click();
new Actions(getDriver()).sendKeys(Keys.ARROW_DOWN).perform();

new Actions(getDriver()).sendKeys(Keys.SPACE).perform();

assertTrue("Row 0 should be selected after pressing space",
isRowSelected(0));

new Actions(getDriver()).sendKeys(Keys.ARROW_DOWN).perform();

new Actions(getDriver()).sendKeys(Keys.SPACE).perform();

assertFalse(
"Row 0 should be deselected after pressing space another row",
isRowSelected(0));
assertTrue("Row 1 should be selected after pressing space",
isRowSelected(1));

new Actions(getDriver()).sendKeys(Keys.SPACE).perform();

assertTrue("Row should remain selected after pressing space again",
isRowSelected(1));
}

private boolean isRowSelected(int index) {
boolean selected = getGridElement().getRow(index).isSelected();
return selected;
}

private void setSelectionModelMulti() {
selectMenuPath("Component", "State", "Selection mode", "multi");
setSelectionModel("multi");
}

private void setSelectionModelSingle() {
selectMenuPath("Component", "State", "Selection mode", "single");
private void setSelectionModelSingle(boolean deselectAllowed) {
String mode = "single";
if (!deselectAllowed) {
mode += " (no deselect)";
}
setSelectionModel(mode);
}

private void setSelectionModelNone() {
selectMenuPath("Component", "State", "Selection mode", "none");
setSelectionModel("none");
}

private void setSelectionModel(String model) {
selectMenuPath("Component", "State", "Selection mode", model);
}
}

+ 35
- 0
uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java View File

@@ -270,6 +270,41 @@ public class GridSelectionTest extends GridBasicFeaturesTest {

}

@Test
public void testToggleDeselectAllowed() {
openTestURL();

setSelectionModelSingle();
// Deselect allowed already enabled

getGridElement().getCell(5, 1).click();
getGridElement().getCell(5, 1).click();
assertFalse("Row should be not selected after two clicks", getRow(5)
.isSelected());

selectMenuPath("Component", "State", "Single select allow deselect");
getGridElement().getCell(5, 1).click();
getGridElement().getCell(5, 1).click();
assertTrue("Row should be selected after two clicks", getRow(5)
.isSelected());

selectMenuPath("Component", "State", "Single select allow deselect");
getGridElement().getCell(5, 1).click();
assertFalse("Row should be not selected after another click", getRow(5)
.isSelected());

// Also verify that state is updated together with the model
setSelectionModelNone();
selectMenuPath("Component", "State", "Single select allow deselect");
setSelectionModelSingle();

getGridElement().getCell(5, 1).click();
getGridElement().getCell(5, 1).click();

assertTrue("Row should stay selected after two clicks", getRow(5)
.isSelected());
}

private void setSelectionModelMulti() {
selectMenuPath("Component", "State", "Selection mode", "multi");
}

+ 10
- 0
uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java View File

@@ -66,6 +66,7 @@ import com.vaadin.client.widget.grid.events.HeaderKeyPressHandler;
import com.vaadin.client.widget.grid.events.HeaderKeyUpHandler;
import com.vaadin.client.widget.grid.events.ScrollEvent;
import com.vaadin.client.widget.grid.events.ScrollHandler;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.client.widget.grid.selection.SelectionModel.None;
import com.vaadin.client.widgets.Grid;
import com.vaadin.client.widgets.Grid.Column;
@@ -468,6 +469,15 @@ public class GridBasicClientFeaturesWidget extends
}
}, selectionModePath);

addMenuCommand("single (no deselect)", new ScheduledCommand() {
@Override
public void execute() {
grid.setSelectionMode(SelectionMode.SINGLE);
((SelectionModel.Single<?>) grid.getSelectionModel())
.setDeselectAllowed(false);
}
}, selectionModePath);

addMenuCommand("none", new ScheduledCommand() {
@Override
public void execute() {

Loading…
Cancel
Save