Checkpoint tree/list stuff:
No more DataSource interface
Added maxSize/increment to SimpleCellList constructor (not fully functional)
Fix tree node size 0 bug


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7748 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/src/com/google/gwt/bikeshed/list/client/SimpleCellList.java b/bikeshed/src/com/google/gwt/bikeshed/list/client/SimpleCellList.java
index aaef117..e0d3e43 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/list/client/SimpleCellList.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/list/client/SimpleCellList.java
@@ -22,9 +22,12 @@
 import com.google.gwt.bikeshed.list.shared.ListModel;
 import com.google.gwt.bikeshed.list.shared.ListRegistration;
 import com.google.gwt.bikeshed.list.shared.SizeChangeEvent;
+import com.google.gwt.dom.client.DivElement;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.Node;
+import com.google.gwt.dom.client.Style.Display;
+import com.google.gwt.dom.client.Style.Visibility;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.Widget;
 
@@ -40,48 +43,34 @@
 
   private final Cell<T> cell;
   private final ArrayList<T> data = new ArrayList<T>();
+  private int increment;
+  private int maxSize;
+  private ListModel<T> model;
+  private final Element showMoreElem;
   private final Element tmpElem;
   private ListRegistration reg;
   private ValueUpdater<T> valueUpdater;
-
-  public SimpleCellList(ListModel<T> model, Cell<T> cell) {
+  
+  public SimpleCellList(ListModel<T> model, Cell<T> cell, int maxSize, int increment) {
+    this.maxSize = maxSize;
+    this.increment = increment;
+    this.model = model;
     this.cell = cell;
+    
     tmpElem = Document.get().createDivElement();
+    
+    showMoreElem = Document.get().createDivElement();
+    showMoreElem.setInnerHTML("<i>Show " + increment + " more</i>");
+    showMoreElem.getStyle().setDisplay(Display.NONE);
 
     // TODO: find some way for cells to communicate what they're interested in.
-    setElement(Document.get().createDivElement());
+    DivElement outerDiv = Document.get().createDivElement();
+    DivElement innerDiv = Document.get().createDivElement();
+    outerDiv.appendChild(innerDiv);
+    outerDiv.appendChild(showMoreElem);
+    setElement(outerDiv);
     sinkEvents(Event.ONCLICK);
     sinkEvents(Event.ONCHANGE);
-
-    // Register for model events.
-    reg = model.addListHandler(new ListHandler<T>() {
-      public void onDataChanged(ListEvent<T> event) {
-        int start = event.getStart(), len = event.getLength();
-        List<T> values = event.getValues();
-        for (int i = 0; i < len; ++i) {
-          data.set(start + i, values.get(i));
-        }
-        render(start, len, values);
-      }
-
-      public void onSizeChanged(SizeChangeEvent event) {
-        int size = event.getSize();
-
-        // Is there no better way than this mess?
-        data.ensureCapacity(size);
-        while (data.size() < size) {
-          data.add(null);
-        }
-        // TODO: This only grows. It needs to shrink as well.
-
-        gc(size);
-        reg.setRangeOfInterest(0, size);
-      }
-    });
-
-    // Start with no range of interest. This will be updated as soon as the
-    // list size changes.
-    reg.setRangeOfInterest(0, 0);
   }
 
   @Override
@@ -97,11 +86,63 @@
       cell.onBrowserEvent(target, data.get(idx), event, valueUpdater);
     }
   }
-
+  
   public void setValueUpdater(ValueUpdater<T> valueUpdater) {
     this.valueUpdater = valueUpdater;
   }
 
+  @Override
+  protected void onLoad() {
+    super.onLoad();
+    
+    // Register for model events.
+    this.reg = model.addListHandler(new ListHandler<T>() {
+      public void onDataChanged(ListEvent<T> event) {
+        int start = event.getStart(), len = event.getLength();
+        List<T> values = event.getValues();
+        for (int i = 0; i < len; ++i) {
+          data.set(start + i, values.get(i));
+        }
+        render(start, len, values);
+      }
+
+      public void onSizeChanged(SizeChangeEvent event) {
+        int size = event.getSize();
+        if (size > maxSize) {
+          showMoreElem.getStyle().clearDisplay();
+        } else {
+          showMoreElem.getStyle().setDisplay(Display.NONE);
+        }
+        
+        int dataSize = data.size();
+        if (size < dataSize) {
+          while (size < dataSize) {
+            data.remove(dataSize - 1);
+            dataSize--;
+          }
+        } else {
+          data.ensureCapacity(size);
+          while (dataSize < size) {
+            data.add(null);
+            dataSize++;
+          }
+        }
+        
+        // TODO: This only grows. It needs to shrink as well.
+        gc(size);
+      }
+    });
+
+    // Request up to maxSize elements
+    reg.setRangeOfInterest(0, maxSize);
+  }
+  
+  @Override
+  protected void onUnload() {
+    this.reg.removeHandler();
+    this.reg = null;
+  }
+
   private void gc(int size) {
     // Remove unused children if the size shrinks.
     int childCount = getElement().getChildCount();
@@ -111,7 +152,7 @@
   }
 
   private void render(int start, int len, List<T> values) {
-    Element parent = getElement();
+    Element parent = getElement().getFirstChildElement();
     int childCount = parent.getChildCount();
 
     // Create innerHTML for the new items.
diff --git a/bikeshed/src/com/google/gwt/bikeshed/list/shared/AbstractListModel.java b/bikeshed/src/com/google/gwt/bikeshed/list/shared/AbstractListModel.java
index f46dba0..43fdca2 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/list/shared/AbstractListModel.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/list/shared/AbstractListModel.java
@@ -82,7 +82,7 @@
     public void setRangeOfInterest(int start, int length) {
       this.start = start;
       this.length = length;
-      onRangeChanged();
+      onRangeChanged(start, length);
     }
 
     protected ListHandler<T> getHandler() {
@@ -126,7 +126,7 @@
   /**
    * Called when a view changes its range of interest.
    */
-  protected abstract void onRangeChanged();
+  protected abstract void onRangeChanged(int start, int length);
 
   /**
    * Inform the views of the total number of items that are available.
diff --git a/bikeshed/src/com/google/gwt/bikeshed/list/shared/AsyncListModel.java b/bikeshed/src/com/google/gwt/bikeshed/list/shared/AsyncListModel.java
index 7631110..4c5f6f7 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/list/shared/AsyncListModel.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/list/shared/AsyncListModel.java
@@ -18,55 +18,31 @@
 import java.util.List;
 
 /**
- * Asynchronous version of a {@link ListModel}.
+ * An implementation of {@link AbstractListModel} that allows the data to be
+ * modified.
  * 
- * @param <T> the data type
+ * @param <T> the data type of records in the list
  */
-public class AsyncListModel<T> extends AbstractListModel<T> {
-
+public abstract class AsyncListModel<T> extends AbstractListModel<T> {
+  
   /**
-   * The source of data for the list model.
+   * Inform the views of the total number of items that are available.
    * 
-   * @param <T> the data type
+   * @param size the new size
+   * @param exact true if the size is exact, false if it is a guess
    */
-  public static interface DataSource<T> {
-
-    /**
-     * Request that the data source pushes new data to the client. The data
-     * source should call {@link #updateViewData} and/or {@link #updateDataSize}
-     * when the data is available.
-     * 
-     * @param listModel the model requesting the data
-     */
-    void requestData(AsyncListModel<T> listModel);
-  }
-
-  /**
-   * The data source.
-   */
-  private DataSource<T> dataSource;
-
-  /**
-   * Construct a new {@link AsyncListModel}.
-   * 
-   * @param dataSource the data source
-   */
-  public AsyncListModel(DataSource<T> dataSource) {
-    this.dataSource = dataSource;
-  }
-
-  @Override
   public void updateDataSize(int size, boolean exact) {
     super.updateDataSize(size, exact);
   }
 
-  @Override
+  /**
+   * Inform the views of the new data.
+   * 
+   * @param start the start index
+   * @param length the length of the data
+   * @param values the data values
+   */
   public void updateViewData(int start, int length, List<T> values) {
     super.updateViewData(start, length, values);
   }
-
-  @Override
-  protected void onRangeChanged() {
-    dataSource.requestData(this);
-  }
 }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/list/shared/ListListModel.java b/bikeshed/src/com/google/gwt/bikeshed/list/shared/ListListModel.java
index 74e8977..574230f 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/list/shared/ListListModel.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/list/shared/ListListModel.java
@@ -222,7 +222,9 @@
   }
 
   @Override
-  protected void onRangeChanged() {
+  protected void onRangeChanged(int start, int length) {
+    // TODO - update size only when needed
+    // TODO - update only relevant range of data
     updateDataSize(listWrapper.size(), true);
     updateViewData(0, listWrapper.size(), listWrapper);
   }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/PlayerScoresWidget.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/PlayerScoresWidget.java
index 14a0067..49c1be2 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/PlayerScoresWidget.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/PlayerScoresWidget.java
@@ -75,6 +75,6 @@
 
   @UiFactory
   SimpleCellList<PlayerInfo> createListView() {
-    return new SimpleCellList<PlayerInfo>(model, new PlayerInfoCell());
+    return new SimpleCellList<PlayerInfo>(model, new PlayerInfoCell(), 1, 1);
   }
 }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java
index 6aa5f9f..ab01470 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java
@@ -19,7 +19,6 @@
 import com.google.gwt.bikeshed.list.shared.AsyncListModel;
 import com.google.gwt.bikeshed.list.shared.ListListModel;
 import com.google.gwt.bikeshed.list.shared.Range;
-import com.google.gwt.bikeshed.list.shared.AsyncListModel.DataSource;
 import com.google.gwt.bikeshed.sample.stocks.client.TransactionTreeViewModel.SectorListModel;
 import com.google.gwt.bikeshed.sample.stocks.shared.PlayerInfo;
 import com.google.gwt.bikeshed.sample.stocks.shared.StockQuote;
@@ -111,26 +110,25 @@
   public void onModuleLoad() {
     // Create the various models. Do this before binding the UI, because some
     // of the UiFactories need the models to instantiate their widgets.
-    searchListModel = new AsyncListModel<StockQuote>(
-        new DataSource<StockQuote>() {
-          public void requestData(AsyncListModel<StockQuote> listModel) {
-            update();
-          }
-        });
+    searchListModel = new AsyncListModel<StockQuote>() {
+      @Override
+      protected void onRangeChanged(int start, int length) {
+        update();
+      }
+    };
 
-    favoritesListModel = new AsyncListModel<StockQuote>(
-        new DataSource<StockQuote>() {
-          public void requestData(AsyncListModel<StockQuote> listModel) {
-            update();
-          }
-        });
+    favoritesListModel = new AsyncListModel<StockQuote>() {
+      @Override
+      protected void onRangeChanged(int start, int length) {
+        update();
+      }
+    };
 
-    playerScoresListModel = new AsyncListModel<PlayerInfo>(
-        new DataSource<PlayerInfo>() {
-          public void requestData(AsyncListModel<PlayerInfo> listModel) {
-            // Player cannot request data from this view.
-          }
-        });
+    playerScoresListModel = new AsyncListModel<PlayerInfo>() {
+      @Override
+      protected void onRangeChanged(int start, int length) {
+      }
+    };
 
     treeModel = new TransactionTreeViewModel(this, favoritesListModel,
         transactionListListModelsByTicker);
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/TransactionTreeViewModel.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/TransactionTreeViewModel.java
index 4983262..039ee98 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/TransactionTreeViewModel.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/TransactionTreeViewModel.java
@@ -42,18 +42,18 @@
 
     String sector;
 
-    public SectorListModel(final Updater updater, String sector) {
-      super(new DataSource<StockQuote>() {
-        public void requestData(AsyncListModel<StockQuote> listModel) {
-          updater.update();
-        }
-      });
+    public SectorListModel(String sector) {
       this.sector = sector;
     }
 
     public String getSector() {
       return sector;
     }
+
+    @Override
+    protected void onRangeChanged(int start, int length) {
+      updater.update();
+    }
   }
 
   static class TransactionCell extends Cell<Transaction> {
@@ -131,7 +131,7 @@
             }
           });
     } else if (value instanceof String) {
-      SectorListModel listModel = new SectorListModel(updater, (String) value);
+      SectorListModel listModel = new SectorListModel((String) value);
       sectorListModels.put((String) value, listModel);
       return new TreeViewModel.DefaultNodeInfo<StockQuote>(listModel, STOCK_QUOTE_CELL) {
         @Override
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/tree/client/MyTreeViewModel.java b/bikeshed/src/com/google/gwt/bikeshed/sample/tree/client/MyTreeViewModel.java
index a4ed1da..61596c3 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/tree/client/MyTreeViewModel.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/tree/client/MyTreeViewModel.java
@@ -18,7 +18,7 @@
 import com.google.gwt.bikeshed.cells.client.ButtonCell;
 import com.google.gwt.bikeshed.cells.client.Cell;
 import com.google.gwt.bikeshed.cells.client.ValueUpdater;
-import com.google.gwt.bikeshed.list.shared.AsyncListModel;
+import com.google.gwt.bikeshed.list.shared.AbstractListModel;
 import com.google.gwt.bikeshed.list.shared.ListModel;
 import com.google.gwt.bikeshed.tree.client.TreeNode;
 import com.google.gwt.bikeshed.tree.client.TreeViewModel;
@@ -35,47 +35,53 @@
  */
 public class MyTreeViewModel implements TreeViewModel {
 
-  private static class IntegerListModel extends AsyncListModel<Integer> {
-    public IntegerListModel(final int length) {
-      super(new DataSource<Integer>() {
-        public void requestData(AsyncListModel<Integer> listModel) {
-          listModel.updateDataSize(1, true);
-          List<Integer> values = new ArrayList<Integer>(1);
-          values.add(length);
-          listModel.updateViewData(0, 1, values);
-        }
-      });
+  private static class IntegerListModel extends AbstractListModel<Integer> {
+    int wordLength;
+    
+    public IntegerListModel(int wordLength) {
+      this.wordLength = wordLength;
+    }
+    
+    @Override
+    protected void onRangeChanged(int start, int length) {
+      List<Integer> values = new ArrayList<Integer>(1);
+      values.add(wordLength);
+      updateDataSize(1, true);
+      updateViewData(0, 1, values);
     }
   }
 
-  private static class StringListModel extends AsyncListModel<String> {
+  private static class StringListModel extends AbstractListModel<String> {
+    String value;
+    
     public StringListModel(final String value) {
-      super(new DataSource<String>() {
-        public void requestData(final AsyncListModel<String> listModel) {
-          String prefix = value.endsWith("...") ? value.substring(0,
-              value.length() - 3) : value;
-          dataService.getNext(prefix, new AsyncCallback<List<String>>() {
-            public void onFailure(Throwable caught) {
-              String message = caught.getMessage();
-              if (message.contains("Not logged in")) {
-                // Force the user to login.
-                Window.Location.reload();
-              } else {
-                Window.alert("ERROR: " + caught.getMessage());
-              }
-            }
+      this.value = value;
+    }
+    
+    @Override
+    protected void onRangeChanged(int start, int length) {
+      String prefix = value.endsWith("...") ? value.substring(0,
+          value.length() - 3) : value;
+      dataService.getNext(prefix, new AsyncCallback<List<String>>() {
+        public void onFailure(Throwable caught) {
+          String message = caught.getMessage();
+          if (message.contains("Not logged in")) {
+            // Force the user to login.
+            Window.Location.reload();
+          } else {
+            Window.alert("ERROR: " + caught.getMessage());
+          }
+        }
 
-            public void onSuccess(final List<String> result) {
-              // Use a timer to simulate network delay.
-              new Timer() {
-                @Override
-                public void run() {
-                  listModel.updateDataSize(result.size(), true);
-                  listModel.updateViewData(0, result.size(), result);
-                }
-              }.schedule(500);
+        public void onSuccess(final List<String> result) {
+          // Use a timer to simulate network delay.
+          new Timer() {
+            @Override
+            public void run() {
+              updateDataSize(result.size(), true);
+              updateViewData(0, result.size(), result);
             }
-          });
+          }.schedule(500);
         }
       });
     }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeNodeView.java b/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeNodeView.java
index 4502c97..3e25271 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeNodeView.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeNodeView.java
@@ -426,8 +426,13 @@
 
       public void onSizeChanged(SizeChangeEvent event) {
         if (event.getSize() == 0 && event.isExact()) {
-          // Close the node
-          setState(false, false);
+          ensureChildContainer().setInnerHTML("<i>no data</i>");
+          if (children != null) {
+            for (TreeNodeView<?> child : children) {
+              child.cleanup();
+            }
+            children = null;
+          }
         }
       }
     });