Adding NoSelectionModel, which allows selection without saving the selection state.

Review at http://gwt-code-reviews.appspot.com/667801

Review by: jgw@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8360 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseList.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseList.java
index 1f3f8ec..0eb922d 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseList.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseList.java
@@ -54,8 +54,8 @@
 import com.google.gwt.valuestore.shared.Property;
 import com.google.gwt.view.client.AsyncListViewAdapter;
 import com.google.gwt.view.client.ListView;
+import com.google.gwt.view.client.NoSelectionModel;
 import com.google.gwt.view.client.Range;
-import com.google.gwt.view.client.SingleSelectionModel;
 import com.google.gwt.view.client.SelectionModel.SelectionChangeEvent;
 import com.google.gwt.view.client.SelectionModel.SelectionChangeHandler;
 
@@ -465,12 +465,12 @@
     table.addColumnStyleName(5, common.spacerColumn());
 
     // Add a selection model.
-    final SingleSelectionModel<ReportRecord> selectionModel = new SingleSelectionModel<ReportRecord>();
+    final NoSelectionModel<ReportRecord> selectionModel = new NoSelectionModel<ReportRecord>();
     table.setSelectionModel(selectionModel);
     table.setSelectionEnabled(true);
     selectionModel.addSelectionChangeHandler(new SelectionChangeHandler() {
       public void onSelectionChange(SelectionChangeEvent event) {
-        Object selected = selectionModel.getSelectedObject();
+        Object selected = selectionModel.getLastSelectedObject();
         if (selected != null && listener != null) {
           listener.onReportSelected((ReportRecord) selected);
         }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/MobileExpenseList.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/MobileExpenseList.java
index 13083ea..e0c5c7b 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/MobileExpenseList.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/MobileExpenseList.java
@@ -27,8 +27,8 @@
 import com.google.gwt.valuestore.shared.Property;
 import com.google.gwt.view.client.AsyncListViewAdapter;
 import com.google.gwt.view.client.ListView;
+import com.google.gwt.view.client.NoSelectionModel;
 import com.google.gwt.view.client.SelectionModel;
-import com.google.gwt.view.client.SingleSelectionModel;
 import com.google.gwt.view.client.SelectionModel.SelectionChangeEvent;
 
 import java.util.ArrayList;
@@ -96,7 +96,7 @@
   private final ExpensesRequestFactory requestFactory;
   private final CellList<ExpenseRecord> expenseList;
   private final AsyncListViewAdapter<ExpenseRecord> expenseAdapter;
-  private final SingleSelectionModel<ExpenseRecord> expenseSelection;
+  private final NoSelectionModel<ExpenseRecord> expenseSelection;
 
   /**
    * The set of Expense keys that we already know are denied. When a new key is
@@ -136,11 +136,11 @@
 
     expenseList = new CellList<ExpenseRecord>(new ExpenseCell());
 
-    expenseSelection = new SingleSelectionModel<ExpenseRecord>();
+    expenseSelection = new NoSelectionModel<ExpenseRecord>();
     expenseList.setSelectionModel(expenseSelection);
     expenseSelection.addSelectionChangeHandler(new SelectionModel.SelectionChangeHandler() {
       public void onSelectionChange(SelectionChangeEvent event) {
-        listener.onExpenseSelected(expenseSelection.getSelectedObject());
+        listener.onExpenseSelected(expenseSelection.getLastSelectedObject());
       }
     });
 
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/MobileReportList.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/MobileReportList.java
index 75d3927..4ebae64 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/MobileReportList.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/MobileReportList.java
@@ -25,8 +25,8 @@
 import com.google.gwt.valuestore.shared.Property;
 import com.google.gwt.view.client.AsyncListViewAdapter;
 import com.google.gwt.view.client.ListView;
+import com.google.gwt.view.client.NoSelectionModel;
 import com.google.gwt.view.client.SelectionModel;
-import com.google.gwt.view.client.SingleSelectionModel;
 import com.google.gwt.view.client.SelectionModel.SelectionChangeEvent;
 
 import java.util.ArrayList;
@@ -56,7 +56,7 @@
   private final Listener listener;
   private final CellList<ReportRecord> reportList;
   private final AsyncListViewAdapter<ReportRecord> reportAdapter;
-  private final SingleSelectionModel<ReportRecord> reportSelection;
+  private final NoSelectionModel<ReportRecord> reportSelection;
   private final ExpensesRequestFactory requestFactory;
 
   public MobileReportList(final Listener listener,
@@ -79,11 +79,11 @@
       }
     });
 
-    reportSelection = new SingleSelectionModel<ReportRecord>();
+    reportSelection = new NoSelectionModel<ReportRecord>();
     reportSelection.setKeyProvider(Expenses.REPORT_RECORD_KEY_PROVIDER);
     reportSelection.addSelectionChangeHandler(new SelectionModel.SelectionChangeHandler() {
       public void onSelectionChange(SelectionChangeEvent event) {
-        listener.onReportSelected(reportSelection.getSelectedObject());
+        listener.onReportSelected(reportSelection.getLastSelectedObject());
       }
     });
 
diff --git a/user/src/com/google/gwt/view/client/NoSelectionModel.java b/user/src/com/google/gwt/view/client/NoSelectionModel.java
new file mode 100644
index 0000000..11fe1ac
--- /dev/null
+++ b/user/src/com/google/gwt/view/client/NoSelectionModel.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * 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.google.gwt.view.client;
+
+import com.google.gwt.view.client.SelectionModel.AbstractSelectionModel;
+
+/**
+ * A selection model that does not allow selection, but fires selection change
+ * events. Use this model if you want to know when a user selects an item, but
+ * do not want the view to update based on the selection.
+ * 
+ * <p>
+ * Note: This class is new and its interface subject to change.
+ * </p>
+ * 
+ * @param <T> the record data type
+ */
+public class NoSelectionModel<T> extends AbstractSelectionModel<T> {
+
+  private Object lastKey;
+  private T lastSelection;
+
+  /**
+   * Gets the object that was last selected.
+   * 
+   * @return the last selected object
+   */
+  public T getLastSelectedObject() {
+    return lastSelection;
+  }
+
+  public boolean isSelected(T object) {
+    return false;
+  }
+
+  public void setSelected(T object, boolean selected) {
+    Object key = getKey(object);
+    if (selected) {
+      lastSelection = object;
+      lastKey = key;
+    } else if (lastKey != null && lastKey.equals(key)) {
+      lastSelection = null;
+      lastKey = null;
+    }
+    scheduleSelectionChangeEvent();
+  }
+}
diff --git a/user/test/com/google/gwt/view/ViewSuite.java b/user/test/com/google/gwt/view/ViewSuite.java
index 688b460..25fef3b 100644
--- a/user/test/com/google/gwt/view/ViewSuite.java
+++ b/user/test/com/google/gwt/view/ViewSuite.java
@@ -23,6 +23,7 @@
 import com.google.gwt.view.client.DefaultSelectionModelTest;
 import com.google.gwt.view.client.ListViewAdapterTest;
 import com.google.gwt.view.client.MultiSelectionModelTest;
+import com.google.gwt.view.client.NoSelectionModelTest;
 import com.google.gwt.view.client.RangeTest;
 import com.google.gwt.view.client.SingleSelectionModelTest;
 
@@ -42,6 +43,7 @@
     suite.addTestSuite(DefaultSelectionModelTest.class);
     suite.addTestSuite(ListViewAdapterTest.class);
     suite.addTestSuite(MultiSelectionModelTest.class);
+    suite.addTestSuite(NoSelectionModelTest.class);
     suite.addTestSuite(RangeTest.class);
     suite.addTestSuite(SingleSelectionModelTest.class);
     return suite;
diff --git a/user/test/com/google/gwt/view/client/NoSelectionModelTest.java b/user/test/com/google/gwt/view/client/NoSelectionModelTest.java
new file mode 100644
index 0000000..615087f
--- /dev/null
+++ b/user/test/com/google/gwt/view/client/NoSelectionModelTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * 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.google.gwt.view.client;
+
+import com.google.gwt.view.client.SelectionModel.SelectionChangeEvent;
+import com.google.gwt.view.client.SelectionModel.SelectionChangeHandler;
+
+/**
+ * Tests for {@link NoSelectionModel}.
+ */
+public class NoSelectionModelTest extends AbstractSelectionModelTest {
+
+  public void testGetLastSelectedObject() {
+    NoSelectionModel<String> model = createSelectionModel();
+    assertNull(model.getLastSelectedObject());
+
+    model.setSelected("test", true);
+    assertEquals("test", model.getLastSelectedObject());
+
+    model.setSelected("test", false);
+    assertNull(model.getLastSelectedObject());
+  }
+
+  public void testSelectedChangeEvent() {
+    NoSelectionModel<String> model = createSelectionModel();
+    SelectionChangeHandler handler = new SelectionChangeHandler() {
+      public void onSelectionChange(SelectionChangeEvent event) {
+        finishTest();
+      }
+    };
+    model.addSelectionChangeHandler(handler);
+
+    delayTestFinish(2000);
+    model.setSelected("test", true);
+  }
+
+  public void testSetSelected() {
+    NoSelectionModel<String> model = createSelectionModel();
+    assertFalse(model.isSelected("test0"));
+
+    model.setSelected("test0", true);
+    assertFalse(model.isSelected("test0"));
+
+    model.setSelected("test1", true);
+    assertFalse(model.isSelected("test1"));
+  }
+
+  public void testSetSelectedWithKeyProvider() {
+    NoSelectionModel<String> model = createSelectionModel();
+    ProvidesKey<String> keyProvider = new ProvidesKey<String>() {
+      public Object getKey(String item) {
+        return item.toUpperCase();
+      }
+    };
+    model.setKeyProvider(keyProvider);
+    assertFalse(model.isSelected("test0"));
+
+    model.setSelected("test0", true);
+    assertEquals("test0", model.getLastSelectedObject());
+    assertFalse(model.isSelected("test0"));
+    assertFalse(model.isSelected("TEST0"));
+
+    model.setSelected("test1", true);
+    assertEquals("test1", model.getLastSelectedObject());
+    assertFalse(model.isSelected("test1"));
+    assertFalse(model.isSelected("TEST1"));
+    assertFalse(model.isSelected("test0"));
+  }
+
+  @Override
+  protected NoSelectionModel<String> createSelectionModel() {
+    return new NoSelectionModel<String>();
+  }
+}