Fixing a bug in Cell Widgets when using the BOUND_TO_SELECTION KeyboardSelectionPolicy in which programmatically deselecting a value makes the value unselectable until the user selects a different value. For example, in the list A, B, C, if you programmatically deselect value B, then value B cannot be selected unless the user selects value A or C first. We now correctly detect this case and update the state with a null selected value, which allows us to detect the change when the user selects value B. Review at http://gwt-code-reviews.appspot.com/1578805 Review by: skybrian@google.com git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10724 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/cellview/client/HasDataPresenter.java b/user/src/com/google/gwt/user/cellview/client/HasDataPresenter.java index 08875c1..a7d87f5 100644 --- a/user/src/com/google/gwt/user/cellview/client/HasDataPresenter.java +++ b/user/src/com/google/gwt/user/cellview/client/HasDataPresenter.java
@@ -1163,7 +1163,7 @@ * or we will have a null selection event while we wait for asynchronous * data to load. */ - if (newKey != null && !newKey.equals(oldKey)) { + if (newKey != null) { // Check both values for selection before setting selection, or the // selection model may resolve state early. boolean oldValueWasSelected = @@ -1171,15 +1171,20 @@ boolean newValueWasSelected = (newValue == null) ? false : selectionModel.isSelected(newValue); - // Deselect the old value. - if (oldValueWasSelected) { - selectionModel.setSelected(oldValue, false); - } - - // Select the new value. - pending.selectedValue = newValue; - if (newValue != null && !newValueWasSelected) { - selectionModel.setSelected(newValue, true); + if (!newKey.equals(oldKey)) { + // Deselect the old value. + if (oldValueWasSelected) { + selectionModel.setSelected(oldValue, false); + } + + // Select the new value. + pending.selectedValue = newValue; + if (newValue != null && !newValueWasSelected) { + selectionModel.setSelected(newValue, true); + } + } else if (!newValueWasSelected) { + // The value was programmatically deselected. + pending.selectedValue = null; } } }
diff --git a/user/test/com/google/gwt/user/cellview/client/HasDataPresenterTest.java b/user/test/com/google/gwt/user/cellview/client/HasDataPresenterTest.java index e6c7fb1..95835c7 100644 --- a/user/test/com/google/gwt/user/cellview/client/HasDataPresenterTest.java +++ b/user/test/com/google/gwt/user/cellview/client/HasDataPresenterTest.java
@@ -630,6 +630,41 @@ } /** + * Test that programmatically deselecting a row works. + */ + public void testSetKeyboardSelectedRowBoundWithDeselect() { + HasData<String> listView = new MockHasData<String>(); + MockView<String> view = new MockView<String>(); + HasDataPresenter<String> presenter = new HasDataPresenter<String>(listView, view, 10, null); + presenter.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.BOUND_TO_SELECTION); + presenter.setVisibleRange(new Range(0, 10)); + populatePresenter(presenter); + presenter.flush(); + + // Add a selection model. + MockSingleSelectionModel<String> model = new MockSingleSelectionModel<String>(null); + presenter.setSelectionModel(model); + presenter.flush(); + assertEquals(null, model.getSelectedObject()); + + // Select an item. + presenter.setKeyboardSelectedRow(1, false, false); + presenter.flush(); + assertTrue(model.isSelected("test 1")); + + // Deselect the item. + model.setSelected("test 1", false); + assertFalse(model.isSelected("test 1")); + presenter.flush(); + assertEquals(1, presenter.getKeyboardSelectedRow()); + + // Reselect the item. + presenter.setKeyboardSelectedRow(1, false, false); + presenter.flush(); + assertTrue(model.isSelected("test 1")); + } + + /** * Test that we only get one selection event when keyboard selection changes. */ public void testSetKeyboardSelectedRowFiresOneSelectionEvent() {