Play with css styling of tree widgets
Make bikeshed compile

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


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7677 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/.classpath b/bikeshed/.classpath
index bf439c1..6386366 100644
--- a/bikeshed/.classpath
+++ b/bikeshed/.classpath
@@ -6,5 +6,6 @@
 	<classpathentry kind="con" path="com.google.gwt.eclipse.core.GWT_CONTAINER"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="lib" path="war/WEB-INF/lib/gwt-servlet.jar"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
 	<classpathentry kind="output" path="war/WEB-INF/classes"/>
 </classpath>
diff --git a/bikeshed/src/com/google/gwt/bikeshed/cells/client/CheckboxCell.java b/bikeshed/src/com/google/gwt/bikeshed/cells/client/CheckboxCell.java
index a085f46..fe98524 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/cells/client/CheckboxCell.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/cells/client/CheckboxCell.java
@@ -40,7 +40,7 @@
   @Override
   public void render(Boolean data, StringBuilder sb) {
     sb.append("<input type=\"checkbox\"");
-    if (data == Boolean.TRUE) {
+    if (data == true) {
       sb.append(" checked");
     }
     sb.append("/>");
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 c2b6210..d74790a 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
@@ -252,7 +252,7 @@
     
     // Create the transactions tree.
     transactionTree2 = new SideBySideTreeView(new TransactionTreeViewModel(favoritesListModel,
-        transactionListListModelsByTicker), null);
+        transactionListListModelsByTicker), null, 200, 200);
 
     Columns.favoriteColumn.setFieldUpdater(new FieldUpdater<StockQuote, Boolean>() {
       public void update(StockQuote object, Boolean value) {
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java
index 332f0ed..8ee31cc 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java
@@ -51,7 +51,7 @@
   /**
    * The result of a query to the remote service that provides stock quotes.
    */
-  private class Result {
+  private static class Result {
     int numRows;
     StockQuoteList quotes;
 
@@ -91,7 +91,7 @@
       throws IllegalArgumentException {
 
     String query = request.getSearchQuery();
-    if (query == null | query.length() == 0) {
+    if (query == null || query.length() == 0) {
       query = ".*";
     }
     Range searchRange = request.getSearchRange();
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/tree/client/TreeSample.java b/bikeshed/src/com/google/gwt/bikeshed/sample/tree/client/TreeSample.java
index 3063d4b..26c93be 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/tree/client/TreeSample.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/tree/client/TreeSample.java
@@ -33,7 +33,7 @@
 
     RootPanel.get().add(new HTML("<hr>"));
     
-    SideBySideTreeView sstree = new SideBySideTreeView(new MyTreeViewModel(), "...");
+    SideBySideTreeView sstree = new SideBySideTreeView(new MyTreeViewModel(), "...", 100, 200);
     RootPanel.get().add(sstree);
   }
 }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/tree/client/SideBySideTreeNodeView.java b/bikeshed/src/com/google/gwt/bikeshed/tree/client/SideBySideTreeNodeView.java
index 8ac9dd9..0e24b53 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/tree/client/SideBySideTreeNodeView.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/tree/client/SideBySideTreeNodeView.java
@@ -15,8 +15,6 @@
  */
 package com.google.gwt.bikeshed.tree.client;
 
-import static com.google.gwt.bikeshed.tree.client.SideBySideTreeView.COLUMN_WIDTH;
-
 import com.google.gwt.bikeshed.cells.client.Cell;
 import com.google.gwt.bikeshed.tree.client.TreeViewModel.NodeInfo;
 import com.google.gwt.dom.client.Document;
@@ -29,11 +27,15 @@
 
 /**
  * A tree view that displays each level in a side-by-side manner.
- * 
+ *
  * @param <T> the type that this {@link TreeNodeView} contains
  */
 public class SideBySideTreeNodeView<T> extends TreeNodeView<T> {
 
+  private int columnHeight;
+
+  private int columnWidth;
+
   private final int imageLeft;
 
   private int level;
@@ -42,7 +44,7 @@
 
   /**
    * Construct a {@link TreeNodeView}.
-   * 
+   *
    * @param tree the parent {@link TreeView}
    * @param parent the parent {@link TreeNodeView}
    * @param parentNodeInfo the {@link NodeInfo} of the parent
@@ -50,33 +52,38 @@
    * @param value the value of this node
    */
   SideBySideTreeNodeView(final TreeView tree, final SideBySideTreeNodeView<?> parent,
-      NodeInfo<T> parentNodeInfo, Element elem, T value, int level, String path) {
+      NodeInfo<T> parentNodeInfo, Element elem, T value, int level, String path,
+      int columnWidth, int columnHeight) {
     super(tree, parent, parentNodeInfo, value);
-    this.imageLeft = 85 - tree.getImageWidth();
+    this.imageLeft = columnWidth - 16 - tree.getImageWidth();
     this.level = level;
     this.path = path;
-    
+    this.columnWidth = columnWidth;
+    this.columnHeight = columnHeight;
+
     setElement(elem);
   }
 
   @Override
   protected <C> TreeNodeView<C> createTreeNodeView(NodeInfo<C> nodeInfo,
       Element childElem, C childValue, int idx) {
-    return new SideBySideTreeNodeView<C>(tree,
-        SideBySideTreeNodeView.this, nodeInfo, childElem, childValue,
-        level + 1, path + "-" + idx);
+    return new SideBySideTreeNodeView<C>(getTree(), this, nodeInfo, childElem,
+        childValue, level + 1, path + "-" + idx, columnWidth, columnHeight);
   }
-  
+
   @Override
-  protected <C> void emitHtml(StringBuilder sb, NodeInfo<C> nodeInfo,
-      List<C> childValues, List<TreeNodeView<?>> savedViews) {
+  protected <C> void emitHtml(StringBuilder sb, List<C> childValues,
+      List<TreeNodeView<?>> savedViews, Cell<C> cell) {
+    TreeView tree = getTree();
     TreeViewModel model = tree.getTreeViewModel();
     int imageWidth = tree.getImageWidth();
-    Cell<C> theCell = nodeInfo.getCell();
 
     int idx = 0;
     for (C childValue : childValues) {
-      sb.append("<div id=\"" + path + "-" + idx + "\" style=\"position:relative;padding-right:");
+      sb.append("<div id=\"" + path + "-" + idx +
+          "\" class=\"gwt-sstree-unselectedItem gwt-sstree-" +
+          ((idx % 2) == 0 ? "even" : "odd") + "Row\"" +
+          " style=\"position:relative;padding-right:");
       sb.append(imageWidth);
       sb.append("px;\">");
       if (savedViews.get(idx) != null) {
@@ -87,31 +94,32 @@
         sb.append(tree.getClosedImageHtml(imageLeft));
       }
       sb.append("<div class=\"gwt-sstree-cell\">");
-      theCell.render(childValue, sb);
+      cell.render(childValue, sb);
       sb.append("</div></div>");
-      
+
       idx++;
     }
   }
 
   /**
    * Ensure that the child container exists and return it.
-   * 
+   *
    * @return the child container
    */
   @Override
   protected Element ensureChildContainer() {
-    if (childContainer == null) {
+    if (getChildContainer() == null) {
       // Create the container within the top-level widget element.
       Element container = createContainer(level);
       container.setInnerHTML("");
       Element animFrame = container.appendChild(
           Document.get().createDivElement());
       animFrame.getStyle().setPosition(Position.RELATIVE);
-      childContainer = animFrame.appendChild(Document.get().createDivElement());
+      animFrame.setId("animFrame");
+      setChildContainer(animFrame.appendChild(Document.get().createDivElement()));
     }
 
-    return childContainer;
+    return getChildContainer();
   }
 
   /**
@@ -121,7 +129,12 @@
   protected Element getCellParent() {
     return getElement().getChild(1).cast();
   }
-  
+
+  @Override
+  protected Element getContainer() {
+    return getTree().getElement().getChild(level).cast();
+  }
+
   /**
    * @return the image element
    */
@@ -134,7 +147,7 @@
   protected int getImageLeft() {
     return imageLeft;
   }
-  
+
   @Override
   protected void postClose() {
     destroyContainer(level);
@@ -151,12 +164,14 @@
 
         TreeNodeView<?> sibling = parentNode.getChildTreeNodeView(i);
         if (sibling == this) {
-          container.setClassName("gwt-SideBySideTree-selectedItem");
+          container.setClassName("gwt-sstree-selectedItem");
         } else {
           if (sibling.getState()) {
             sibling.setState(false);
-            container.setClassName("gwt-SideBySideTree-unselectedItem");
           }
+
+          container.setClassName("gwt-sstree-unselectedItem " +
+              (((i % 2) == 0) ? "gwt-sstree-evenRow" : "gwt-sstree-oddRow"));
         }
       }
     }
@@ -167,22 +182,24 @@
    */
   private Element createContainer(int level) {
     // Resize the root element
-    Element rootElement = tree.getElement();
-    rootElement.getStyle().setWidth((level + 1) * COLUMN_WIDTH, Unit.PX);
-    
+    Element rootElement = getTree().getElement();
+    rootElement.getStyle().setWidth((level + 1) * columnWidth, Unit.PX);
+
     // Create children of the root container as needed.
     int childCount = rootElement.getChildCount();
     while (childCount <= level) {
       Element div = rootElement.appendChild(Document.get().createDivElement());
-      div.setClassName("gwt-SideBySideTreeColumn");
+      div.setClassName("gwt-sstree-column");
       Style style = div.getStyle();
       style.setPosition(Position.ABSOLUTE);
       style.setTop(0, Unit.PX);
-      style.setLeft(level * COLUMN_WIDTH, Unit.PX);
-      
+      style.setLeft(level * columnWidth, Unit.PX);
+      style.setWidth(columnWidth, Unit.PX);
+      style.setHeight(columnHeight, Unit.PX);
+
       childCount++;
     }
-    
+
     return rootElement.getChild(level).cast();
   }
 
@@ -192,16 +209,16 @@
    */
   private void destroyContainer(int level) {
     // Resize the root element
-    Element rootElement = tree.getElement();
-    rootElement.getStyle().setWidth((level + 1) * COLUMN_WIDTH, Unit.PX);
-    
+    Element rootElement = getTree().getElement();
+    rootElement.getStyle().setWidth((level + 1) * columnWidth, Unit.PX);
+
     // Create children of the root container as needed.
     int childCount = rootElement.getChildCount();
     while (childCount > level) {
       rootElement.removeChild(rootElement.getLastChild());
       childCount--;
     }
-    
-    childContainer = null;
+
+    setChildContainer(null);
   }
 }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/tree/client/SideBySideTreeView.java b/bikeshed/src/com/google/gwt/bikeshed/tree/client/SideBySideTreeView.java
index cab7067..f8cd50d 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/tree/client/SideBySideTreeView.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/tree/client/SideBySideTreeView.java
@@ -27,27 +27,33 @@
  * A view of a tree.
  */
 public class SideBySideTreeView extends TreeView {
-  
-  protected static final int COLUMN_HEIGHT = 200;
 
-  protected static final int COLUMN_WIDTH = 100;
+  protected int columnHeight = 200;
+
+  protected int columnWidth = 100;
 
   /**
    * Construct a new {@link TreeView}.
-   * 
+   *
    * @param <T> the type of data in the root node
    * @param viewModel the {@link TreeViewModel} that backs the tree
    * @param rootValue the hidden root value of the tree
+   * @param columnWidth
+   * @param columnHeight
    */
-  public <T> SideBySideTreeView(TreeViewModel viewModel, T rootValue) {
+  public <T> SideBySideTreeView(TreeViewModel viewModel, T rootValue,
+      int columnWidth, int columnHeight) {
     super(viewModel);
-    
+
+    this.columnWidth = columnWidth;
+    this.columnHeight = columnHeight;
+
     Element rootElement = Document.get().createDivElement();
-    rootElement.setClassName("gwt-SideBySideTreeView");
+    rootElement.setClassName("gwt-sstree");
     Style style = rootElement.getStyle();
     style.setPosition(Position.RELATIVE);
-    style.setWidth(COLUMN_WIDTH, Unit.PX);
-    style.setHeight(COLUMN_HEIGHT, Unit.PX);
+    style.setWidth(columnWidth, Unit.PX);
+    style.setHeight(columnHeight, Unit.PX);
     setElement(rootElement);
 
     // Add event handlers.
@@ -55,7 +61,7 @@
 
     // Associate a view with the item.
     TreeNodeView<T> root = new SideBySideTreeNodeView<T>(this, null, null,
-        rootElement, rootValue, 0, "gwt-sstree");
+        rootElement, rootValue, 0, "gwt-sstree", columnWidth, columnHeight);
     setRootNode(root);
     root.setState(true);
   }
@@ -86,7 +92,7 @@
             id = id.substring(11);
             String[] path = id.split("-");
 
-            TreeNodeView<?> nodeView = rootNode;
+            TreeNodeView<?> nodeView = getRootNode();
             for (String s : path) {
               nodeView = nodeView.getChildTreeNodeView(Integer.parseInt(s));
             }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/tree/client/StandardTreeNodeView.java b/bikeshed/src/com/google/gwt/bikeshed/tree/client/StandardTreeNodeView.java
index fcdb562..f7a53c4 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/tree/client/StandardTreeNodeView.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/tree/client/StandardTreeNodeView.java
@@ -26,14 +26,14 @@
 
 /**
  * A view of a tree node.
- * 
+ *
  * @param <T> the type that this {@link TreeNodeView} contains
  */
 public class StandardTreeNodeView<T> extends TreeNodeView<T> {
 
   /**
    * Construct a {@link TreeNodeView}.
-   * 
+   *
    * @param tree the parent {@link TreeView}
    * @param parent the parent {@link TreeNodeView}
    * @param parentNodeInfo the {@link NodeInfo} of the parent
@@ -46,26 +46,26 @@
     super(tree, parent, parentNodeInfo, value);
     setElement(elem);
   }
-  
+
   @Override
   protected void postClose() {
-    tree.maybeAnimateTreeNode(this);
+    getTree().maybeAnimateTreeNode(this);
   }
 
   @Override
   protected <C> TreeNodeView<C> createTreeNodeView(NodeInfo<C> nodeInfo,
       Element childElem, C childValue, int idx) {
-    return new StandardTreeNodeView<C>(tree, this, nodeInfo, childElem,
+    return new StandardTreeNodeView<C>(getTree(), this, nodeInfo, childElem,
         childValue);
   }
 
   @Override
-  protected <C> void emitHtml(StringBuilder sb, NodeInfo<C> nodeInfo,
-      List<C> childValues, List<TreeNodeView<?>> savedViews) {
+  protected <C> void emitHtml(StringBuilder sb, List<C> childValues,
+      List<TreeNodeView<?>> savedViews, Cell<C> cell) {
+    TreeView tree = getTree();
     TreeViewModel model = tree.getTreeViewModel();
     int imageWidth = tree.getImageWidth();
-    Cell<C> theCell = nodeInfo.getCell();
-    
+
     int idx = 0;
     for (C childValue : childValues) {
       sb.append("<div style=\"position:relative;padding-left:");
@@ -79,28 +79,28 @@
         sb.append(tree.getClosedImageHtml(0));
       }
       sb.append("<div>");
-      theCell.render(childValue, sb);
-      sb.append("</div>");
-      sb.append("</div>");
+      cell.render(childValue, sb);
+      sb.append("</div></div>");
     }
   }
 
   /**
    * Ensure that the child container exists and return it.
-   * 
+   *
    * @return the child container
    */
   @Override
   protected Element ensureChildContainer() {
-    if (childContainer == null) {
+    if (getChildContainer() == null) {
       // If this is a root node or the element does not exist, create it.
       Element animFrame = getElement().appendChild(
           Document.get().createDivElement());
       animFrame.getStyle().setPosition(Position.RELATIVE);
       animFrame.getStyle().setOverflow(Overflow.HIDDEN);
-      childContainer = animFrame.appendChild(Document.get().createDivElement());
+      animFrame.setId("animFrame");
+      setChildContainer(animFrame.appendChild(Document.get().createDivElement()));
     }
-    return childContainer;
+    return getChildContainer();
   }
 
   /**
@@ -110,7 +110,7 @@
   protected Element getCellParent() {
     return getElement().getChild(1).cast();
   }
-  
+
   /**
    * @return the image element
    */
diff --git a/bikeshed/src/com/google/gwt/bikeshed/tree/client/StandardTreeView.java b/bikeshed/src/com/google/gwt/bikeshed/tree/client/StandardTreeView.java
index 241cfcb..2a3665b 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/tree/client/StandardTreeView.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/tree/client/StandardTreeView.java
@@ -39,7 +39,7 @@
 
     /**
      * Create a new {@link RevealAnimation}.
-     * 
+     *
      * @return the new animation
      */
     public static RevealAnimation create() {
@@ -72,7 +72,7 @@
 
     /**
      * Animate a {@link TreeNodeView} into its new state.
-     * 
+     *
      * @param node the {@link TreeNodeView} to animate
      * @param isAnimationEnabled true to animate
      */
@@ -151,7 +151,7 @@
   public static class SlideAnimation extends RevealAnimation {
     /**
      * Create a new {@link RevealAnimation}.
-     * 
+     *
      * @return the new animation
      */
     public static SlideAnimation create() {
@@ -198,7 +198,7 @@
 
   /**
    * Construct a new {@link TreeView}.
-   * 
+   *
    * @param <T> the type of data in the root node
    * @param viewModel the {@link TreeViewModel} that backs the tree
    * @param rootValue the hidden root value of the tree
@@ -209,8 +209,8 @@
     setStyleName("gwt-TreeView");
 
     // We use one animation for the entire tree.
-    animation = SlideAnimation.create();
-    
+    setAnimation(SlideAnimation.create());
+
     // Add event handlers.
     sinkEvents(Event.ONCLICK | Event.ONMOUSEDOWN | Event.ONMOUSEUP);
 
@@ -230,7 +230,7 @@
         Element currentTarget = event.getCurrentEventTarget().cast();
         if (currentTarget == getElement()) {
           Element target = event.getEventTarget().cast();
-          elementClicked(target, event, rootNode);
+          elementClicked(target, event, getRootNode());
         }
         break;
     }
@@ -268,13 +268,13 @@
 
     return false;
   }
-  
+
   private TreeNodeView<?> findItemByChain(ArrayList<Element> chain, int idx,
       TreeNodeView<?> parent) {
     if (idx == chain.size()) {
       return parent;
     }
-  
+
     Element hCurElem = chain.get(idx);
     for (int i = 0, n = parent.getChildCount(); i < n; ++i) {
       TreeNodeView<?> child = parent.getChildTreeNodeView(i);
@@ -286,7 +286,7 @@
         return retItem;
       }
     }
-  
+
     return findItemByChain(chain, idx + 1, parent);
   }
 }
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 1ba192c..87211c6 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeNodeView.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeNodeView.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.bikeshed.tree.client;
 
+import com.google.gwt.bikeshed.cells.client.Cell;
 import com.google.gwt.bikeshed.list.shared.ListEvent;
 import com.google.gwt.bikeshed.list.shared.ListHandler;
 import com.google.gwt.bikeshed.list.shared.ListModel;
@@ -35,7 +36,7 @@
 
 /**
  * A view of a tree node.
- * 
+ *
  * @param <T> the type that this {@link TreeNodeView} contains
  */
 public abstract class TreeNodeView<T> extends Composite implements TreeNode<T> {
@@ -43,55 +44,58 @@
   /**
    * The element used in place of an image when a node has no children.
    */
-  protected static final String LEAF_IMAGE = "<div style='position:absolute;display:none;'></div>";
-  
-  protected boolean animate;
+  public static final String LEAF_IMAGE = "<div style='position:absolute;display:none;'></div>";
 
   /**
    * A reference to the element that contains the children.
    */
-  protected Element childContainer;
+  private Element childContainer;
 
   /**
-   * The children of this {@link TreeNodeView}.
+   * True during the time a node should be animated.
    */
-  protected List<TreeNodeView<?>> children;
-  
+  private boolean animate;
+
+  /**
+   * A reference to the element that contains the children.
+   */
+  private List<TreeNodeView<?>> children;
+
   /**
    * The list registration for the list of children.
    */
-  protected ListRegistration listReg;
-  
+  private ListRegistration listReg;
+
   /**
    * The info about children of this node.
    */
-  protected NodeInfo<?> nodeInfo;
+  private NodeInfo<?> nodeInfo;
 
   /**
    * Indicates whether or not we've loaded the node info.
    */
-  protected boolean nodeInfoLoaded;
+  private boolean nodeInfoLoaded;
 
   /**
    * Indicates whether or not this node is open.
    */
-  protected boolean open;
-
-  /**
-   * The containing {@link TreeView}.
-   */
-  protected TreeView tree;
+  private boolean open;
 
   /**
    * The parent {@link SideBySideTreeNodeView}.
    */
-  private TreeNodeView<?> parentNode;
-  
+  private final TreeNodeView<?> parentNode;
+
+  /**
+   * The parent {@link SideBySideTreeNodeView}.
+   */
+  private final NodeInfo<T> parentNodeInfo;
+
   /**
    * The info about this node.
    */
-  private NodeInfo<T> parentNodeInfo;
-  
+  private final TreeView tree;
+
   /**
    * This node's value.
    */
@@ -103,7 +107,7 @@
     this.parentNodeInfo = parentNodeInfo;
     this.value = value;
   }
-  
+
   public int getChildCount() {
     return children == null ? 0 : children.size();
   }
@@ -126,7 +130,7 @@
 
   /**
    * Check whether or not this {@link TreeNodeView} is open.
-   * 
+   *
    * @return true if open, false if closed
    */
   public boolean getState() {
@@ -135,7 +139,7 @@
 
   /**
    * Get the value contained in this node.
-   * 
+   *
    * @return the value of the node
    */
   public T getValue() {
@@ -144,16 +148,16 @@
 
   /**
    * Check if this is a root node at the top of the tree.
-   * 
+   *
    * @return true if a root node, false if not
    */
   public boolean isRootNode() {
     return getParentNode() == null;
   }
-  
+
   /**
    * Sets whether this item's children are displayed.
-   * 
+   *
    * @param open whether the item is open
    */
   public void setState(boolean open) {
@@ -162,7 +166,7 @@
 
   /**
    * Sets whether this item's children are displayed.
-   * 
+   *
    * @param open whether the item is open
    * @param fireEvents <code>true</code> to allow open/close events to be
    */
@@ -173,7 +177,7 @@
     if (this.open == open) {
       return;
     }
-    
+
     this.animate = true;
     this.open = open;
     if (open) {
@@ -181,12 +185,12 @@
         nodeInfo = tree.getTreeViewModel().getNodeInfo(getValue(), this);
         nodeInfoLoaded = true;
       }
-      
+
       preOpen();
       // If we don't have any nodeInfo, we must be a leaf node.
       if (nodeInfo != null) {
         onOpen(nodeInfo);
-      } 
+      }
     } else {
       cleanup();
       postClose();
@@ -195,7 +199,7 @@
     // Update the image.
     updateImage();
   }
-  
+
   /**
    * Unregister the list handler and destroy all child nodes.
    */
@@ -205,7 +209,7 @@
       listReg.removeHandler();
       listReg = null;
     }
-  
+
     // Recursively kill children.
     if (children != null) {
       for (TreeNodeView<?> child : children) {
@@ -214,22 +218,44 @@
       children = null;
     }
   }
-  
+
   protected boolean consumeAnimate() {
     boolean hasAnimate = animate;
     animate = false;
     return hasAnimate;
   }
-  
+
+  /**
+   * Returns an instance of TreeNodeView of the same subclass as the
+   * calling object.
+   *
+   * @param <C> the data type of the node's children.
+   * @param nodeInfo a NodeInfo object describing the child nodes.
+   * @param childElem the DOM element used to parent the new TreeNodeView.
+   * @param childValue the child's value.
+   * @param idx the index of the child within its parent node.
+   * @return a TreeNodeView of suitable type.
+   */
   protected abstract <C> TreeNodeView<C> createTreeNodeView(NodeInfo<C> nodeInfo,
       Element childElem, C childValue, int idx);
 
-  protected abstract <C> void emitHtml(StringBuilder sb, NodeInfo<C> nodeInfo,
-      List<C> childValues, List<TreeNodeView<?>> savedViews);
+  /**
+   * Write the HTML for a list of child values into the given StringBuilder.
+   *
+   * @param <C> the data type of the child nodes.
+   * @param sb a StringBuilder to write to.
+   * @param childValues a List of child node values.
+   * @param savedViews a List of TreeNodeView instances corresponding to
+   *   the child values; a non-null value indicates a TreeNodeView previously
+   *   associated with a given child value.
+   * @param cell the Cell to use for rendering each child value.
+   */
+  protected abstract <C> void emitHtml(StringBuilder sb, List<C> childValues,
+      List<TreeNodeView<?>> savedViews, Cell<C> cell);
 
   /**
    * Ensure that the animation frame exists and return it.
-   * 
+   *
    * @return the animation frame
    */
   protected Element ensureAnimationFrame() {
@@ -238,14 +264,14 @@
 
   /**
    * Ensure that the child container exists and return it.
-   * 
+   *
    * @return the child container
    */
   protected abstract Element ensureChildContainer();
 
   /**
    * Fire an event to the {@link com.google.gwt.bikeshed.cells.client.Cell}.
-   * 
+   *
    * @param event the native event
    */
   protected void fireEventToCell(NativeEvent event) {
@@ -256,7 +282,7 @@
       Window.alert("parentNodeInfo == null");
     }
   }
-  
+
   /**
    * Returns the element that parents the cell contents of this node.
    */
@@ -268,7 +294,15 @@
   protected Element getChildContainer() {
     return childContainer;
   }
-  
+
+  /**
+   * Returns the element that contains this node.
+   * The default implementation returns the value of getElement().
+   */
+  protected Element getContainer() {
+    return getElement();
+  }
+
   /**
    * Returns the element corresponding to the open/close image.
    */
@@ -281,7 +315,7 @@
   protected int getImageLeft() {
     return 0;
   }
-  
+
   /**
    * Returns the nodeInfo for this node's parent.
    */
@@ -296,11 +330,11 @@
   protected Object getValueKey() {
     return getParentNodeInfo().getKey(getValue());
   }
-  
+
   /**
    * Set up the node when it is opened.  Delegates to createMap(), emitHtml(),
    * and createTreeNodeView() for subclass-specific functionality.
-   * 
+   *
    * @param nodeInfo the {@link NodeInfo} that provides information about the
    *          child values
    * @param <C> the child data type of the node.
@@ -309,11 +343,11 @@
     // Add a loading message.
     ensureChildContainer().setInnerHTML(tree.getLoadingHtml());
     ensureAnimationFrame().getStyle().setProperty("display", "");
-    
+
     // Get the node info.
     ListModel<C> listModel = nodeInfo.getListModel();
     listReg = listModel.addListHandler(new ListHandler<C>() {
-      public void onDataChanged(ListEvent<C> event) {    
+      public void onDataChanged(ListEvent<C> event) {
         // TODO - handle event start and length
 
         // Construct a map of former child views based on their value keys.
@@ -327,7 +361,7 @@
             }
           }
         }
-        
+
         // Hide the child container so we can animate it.
         if (tree.isAnimationEnabled()) {
           ensureAnimationFrame().getStyle().setDisplay(Display.NONE);
@@ -339,14 +373,14 @@
           // so the call to setInnerHtml will not destroy them
           TreeNodeView<?> savedView = map.get(nodeInfo.getKey(childValue));
           if (savedView != null) {
-            savedView.getElement().removeFromParent();
+            savedView.getContainer().getFirstChild().removeFromParent();
           }
           savedViews.add(savedView);
         }
 
         // Construct the child contents.
         StringBuilder sb = new StringBuilder();
-        emitHtml(sb, nodeInfo, event.getValues(), savedViews);
+        emitHtml(sb, event.getValues(), savedViews, nodeInfo.getCell());
         childContainer.setInnerHTML(sb.toString());
 
         // Create the child TreeNodeViews from the new elements.
@@ -367,12 +401,13 @@
             child.open = savedChild.getState();
 
             // Copy the child container element to the new child
-            child.getElement().appendChild(savedChild.childContainer.getParentElement());
+            // TODO(rice) clean up this expression
+            child.getContainer().appendChild(savedChild.childContainer.getParentElement());
           }
 
           children.add(child);
           childElem = childElem.getNextSiblingElement();
-          
+
           idx++;
         }
 
@@ -400,6 +435,10 @@
   protected void preOpen() {
   }
 
+  protected void setChildContainer(Element childContainer) {
+    this.childContainer = childContainer;
+  }
+
   /**
    * Update the image based on the current state.
    */
@@ -420,4 +459,8 @@
     Element imageElem = tmp.getFirstChildElement();
     getElement().replaceChild(imageElem, getImageElement());
   }
+
+  TreeView getTree() {
+    return tree;
+  }
 }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeView.java b/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeView.java
index 17dd5c9..c29fa37 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeView.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeView.java
@@ -44,7 +44,7 @@
 
     /**
      * Animate a {@link TreeNodeView} into its new state.
-     * 
+     *
      * @param node the {@link TreeNodeView} to animate
      * @param isAnimationEnabled true to animate
      */
@@ -54,12 +54,12 @@
     public int getDuration() {
       return duration;
     }
-    
+
     public void setDuration(int duration) {
       this.duration = duration;
     }
   }
-  
+
   /**
    * A ClientBundle that provides images for this widget.
    */
@@ -77,22 +77,17 @@
   }
 
   private static final Resources DEFAULT_RESOURCES = GWT.create(Resources.class);
- 
+
   /**
    * The animation.
    */
-  protected TreeNodeViewAnimation animation;
-  
-  /**
-   * The hidden root node in the tree.
-   */
-  protected TreeNodeView<?> rootNode;
+  private TreeNodeViewAnimation animation;
 
   /**
    * The HTML used to generate the closed image.
    */
   private String closedImageHtml;
-  
+
   /**
    * Indicates whether or not animations are enabled.
    */
@@ -113,10 +108,15 @@
    * The HTML used to generate the open image.
    */
   private String openImageHtml;
- 
+
+  /**
+   * The hidden root node in the tree.
+   */
+  private TreeNodeView<?> rootNode;
+
   /**
    * Construct a new {@link TreeView}.
-   * 
+   *
    * @param viewModel the {@link TreeViewModel} that backs the tree
    */
   public TreeView(TreeViewModel viewModel) {
@@ -126,14 +126,14 @@
   /**
    * Get the animation used to open and close nodes in this tree if animations
    * are enabled.
-   * 
+   *
    * @return the animation
    * @see #isAnimationEnabled()
    */
-  public Animation getAnimation() {
+  public TreeNodeViewAnimation getAnimation() {
     return animation;
   }
-  
+
   public TreeViewModel getTreeViewModel() {
     return model;
   }
@@ -141,11 +141,11 @@
   public boolean isAnimationEnabled() {
     return isAnimationEnabled;
   }
-  
+
   /**
    * Set the animation used to open and close nodes in this tree. You must call
    * {@link #setAnimationEnabled(boolean)} to enable or disable animation.
-   * 
+   *
    * @param animation a {@link TreeNodeViewAnimation}.
    * @see #setAnimationEnabled(boolean)
    */
@@ -153,7 +153,7 @@
     assert animation != null : "animation cannot be null";
     this.animation = animation;
   }
-  
+
   public void setAnimationEnabled(boolean enable) {
     this.isAnimationEnabled = enable;
     if (!enable && animation != null) {
@@ -177,7 +177,7 @@
 
   /**
    * Get the width required for the images.
-   * 
+   *
    * @return the maximum width required for images.
    */
   protected int getImageWidth() {
@@ -188,13 +188,13 @@
   /**
    * Get the HTML string that is displayed while nodes wait for their children
    * to load.
-   * 
+   *
    * @return the loading HTML string
    */
   protected String getLoadingHtml() {
     return loadingHtml;
   }
-  
+
   /**
    * @return the HTML to render the open image.
    */
@@ -210,9 +210,13 @@
     return openImageHtml;
   }
 
+  protected TreeNodeView<?> getRootNode() {
+    return rootNode;
+  }
+
   /**
    * Animate the current state of a {@link TreeNodeView} in this tree.
-   * 
+   *
    * @param node the node to animate
    */
   protected void maybeAnimateTreeNode(TreeNodeView<?> node) {
@@ -224,18 +228,14 @@
   /**
    * Set the HTML string that will be displayed when a node is waiting for its
    * child nodes to load.
-   * 
+   *
    * @param loadingHtml the HTML string
    */
   protected void setLoadingHtml(String loadingHtml) {
     this.loadingHtml = loadingHtml;
   }
 
-  TreeNodeView<?> getRootNode() {
-    return rootNode;
-  }
-
-  void setRootNode(TreeNodeView<?> rootNode) {
+  protected void setRootNode(TreeNodeView<?> rootNode) {
     this.rootNode = rootNode;
   }
 }
diff --git a/bikeshed/war/Stocks.css b/bikeshed/war/Stocks.css
index 37018e6..7a8f49d 100644
--- a/bikeshed/war/Stocks.css
+++ b/bikeshed/war/Stocks.css
@@ -1,25 +1,27 @@
 /** Add css rules here for your application. */
 
-div.gwt-SideBySideTreeColumn {
-  width: 100px;
-  height: 200px;
+div.gwt-sstree-column {
   overflow-y: scroll;
   overflow-x: auto;
   position: relative;
 }
 
-div.gwt-SideBySideTreeView {
+div.gwt-sstree {
   border: 2px solid black;
 }
 
-div.gwt-SideBySideTree-selectedItem {
+div.gwt-sstree-selectedItem {
   background-color: rgb(56, 117, 215);
 }
 
-div.gwt-SideBySideTree-unselectedItem {
+div.gwt-sstree-evenRow {
   background-color: rgb(255, 255, 255);
 }
 
+div.gwt-sstree-oddRow {
+    background-color: rgb(220, 220, 220);
+}
+
 /** Example rules used by the template application (remove for your app) */
 h1 {
   font-size: 2em;
diff --git a/bikeshed/war/Tree.css b/bikeshed/war/Tree.css
index 37018e6..7a8f49d 100644
--- a/bikeshed/war/Tree.css
+++ b/bikeshed/war/Tree.css
@@ -1,25 +1,27 @@
 /** Add css rules here for your application. */
 
-div.gwt-SideBySideTreeColumn {
-  width: 100px;
-  height: 200px;
+div.gwt-sstree-column {
   overflow-y: scroll;
   overflow-x: auto;
   position: relative;
 }
 
-div.gwt-SideBySideTreeView {
+div.gwt-sstree {
   border: 2px solid black;
 }
 
-div.gwt-SideBySideTree-selectedItem {
+div.gwt-sstree-selectedItem {
   background-color: rgb(56, 117, 215);
 }
 
-div.gwt-SideBySideTree-unselectedItem {
+div.gwt-sstree-evenRow {
   background-color: rgb(255, 255, 255);
 }
 
+div.gwt-sstree-oddRow {
+    background-color: rgb(220, 220, 220);
+}
+
 /** Example rules used by the template application (remove for your app) */
 h1 {
   font-size: 2em;