Unifies small bikeshed samples into a single "cookbook" app.


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7901 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/src/com/google/gwt/bikeshed/list/shared/SelectionModel.java b/bikeshed/src/com/google/gwt/bikeshed/list/shared/SelectionModel.java
index 8bc91bf..3b3a0ee 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/list/shared/SelectionModel.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/list/shared/SelectionModel.java
@@ -102,7 +102,7 @@
    *
    * @param <T> the data type of records in the list
    */
-  abstract class AbstractSelectionModel<T> implements SelectionModel<T> {
+  public abstract class AbstractSelectionModel<T> implements SelectionModel<T> {
 
     private final HandlerManager handlerManager = new HandlerManager(this);
 
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 e9de9a8..6552e68 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/tree/client/StandardTreeView.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/tree/client/StandardTreeView.java
@@ -17,11 +17,9 @@
 
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.dom.client.Style.Display;
 import com.google.gwt.dom.client.Style.Position;
 import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.HasAnimation;
 
@@ -224,15 +222,30 @@
   public void onBrowserEvent(Event event) {
     super.onBrowserEvent(event);
 
-    int eventType = DOM.eventGetType(event);
-    switch (eventType) {
-      case Event.ONMOUSEUP: case Event.ONCHANGE:
-        Element currentTarget = event.getCurrentEventTarget().cast();
-        if (currentTarget == getElement()) {
-          Element target = event.getEventTarget().cast();
-          elementClicked(target, event, getRootTreeNodeView());
+    Element target = event.getEventTarget().cast();
+    TreeNodeView<?> rootNode = getRootTreeNodeView();
+
+    ArrayList<Element> chain = new ArrayList<Element>();
+    ArrayList<String> ids = new ArrayList<String>();
+    collectElementChain(chain, ids, getElement(), target);
+
+    TreeNodeView<?> nodeView = findItemByChain(chain, 0, rootNode);
+    if (nodeView != null && nodeView != rootNode) {
+      if (nodeView.getImageElement().isOrHasChild(target)) {
+        if ("click".equals(event.getType())) {
+          nodeView.setState(!nodeView.getState());
         }
-        break;
+      } else if (nodeView.getCellParent().isOrHasChild(target)) {
+        nodeView.fireEventToCell(event);
+
+        // TODO(jgw): Kind of a hacky way to set selection. Need to generalize
+        // this to some sort of keyboard/mouse->selection controller.
+        if (getSelectionModel() != null) {
+          if ("click".equals(event.getType())) {
+            getSelectionModel().setSelected(nodeView.getValue(), true);
+          }
+        }
+      }
     }
   }
 
@@ -250,25 +263,6 @@
     ids.add(hElem.getId());
   }
 
-  private boolean elementClicked(Element hElem, NativeEvent event, TreeNodeView<?> rootNode) {
-    ArrayList<Element> chain = new ArrayList<Element>();
-    ArrayList<String> ids = new ArrayList<String>();
-    collectElementChain(chain, ids, getElement(), hElem);
-
-    TreeNodeView<?> nodeView = findItemByChain(chain, 0, rootNode);
-    if (nodeView != null && nodeView != rootNode) {
-      if (nodeView.getImageElement().isOrHasChild(hElem)) {
-        nodeView.setState(!nodeView.getState());
-        return true;
-      } else if (nodeView.getCellParent().isOrHasChild(hElem)) {
-        nodeView.fireEventToCell(event);
-        return true;
-      }
-    }
-
-    return false;
-  }
-
   private TreeNodeView<?> findItemByChain(ArrayList<Element> chain, int idx,
       TreeNodeView<?> parent) {
     if (idx == chain.size()) {
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/Cookbook.gwt.xml b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/Cookbook.gwt.xml
new file mode 100644
index 0000000..46f0103
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/Cookbook.gwt.xml
@@ -0,0 +1,7 @@
+<module rename-to='cookbook'>
+  <inherits name='com.google.gwt.user.User'/>
+  <inherits name='com.google.gwt.bikeshed.list.List'/>
+  <inherits name='com.google.gwt.bikeshed.tree.Tree'/>
+
+  <entry-point class='com.google.gwt.sample.bikeshed.cookbook.client.Cookbook'/>
+</module>
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeService.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/BasicTableRecipe.java
similarity index 60%
copy from bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeService.java
copy to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/BasicTableRecipe.java
index 8b245bf..7196040 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeService.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/BasicTableRecipe.java
@@ -13,18 +13,23 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.tree.client;
+package com.google.gwt.sample.bikeshed.cookbook.client;
 
-import com.google.gwt.user.client.rpc.RemoteService;
-import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
-
-import java.util.List;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
 
 /**
- * The client side stub for the RPC service.
+ * Basic table recipe.
  */
-@RemoteServiceRelativePath("tree")
-public interface TreeService extends RemoteService {
-  
-  List<String> getNext(String prefix);
+public class BasicTableRecipe extends Recipe {
+
+  public BasicTableRecipe() {
+    super("Basic Table");
+  }
+
+  @Override
+  protected Widget createWidget() {
+    // TODO
+    return new Label("Basic table demo...");
+  }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/BasicTreeRecipe.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/BasicTreeRecipe.java
new file mode 100644
index 0000000..d718c70
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/BasicTreeRecipe.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.sample.bikeshed.cookbook.client;
+
+import com.google.gwt.bikeshed.list.shared.SelectionModel;
+import com.google.gwt.bikeshed.list.shared.SelectionModel.SelectionChangeEvent;
+import com.google.gwt.bikeshed.tree.client.StandardTreeView;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Basic tree recipe.
+ */
+public class BasicTreeRecipe extends Recipe {
+
+  public BasicTreeRecipe() {
+    super("Basic Tree");
+  }
+
+  @Override
+  protected Widget createWidget() {
+    FlowPanel p = new FlowPanel();
+
+    final Label label = new Label();
+    final MultiSelectionModel<Object> selectionModel = new MultiSelectionModel<Object>();
+    selectionModel.addSelectionChangeHandler(new SelectionModel.SelectionChangeHandler() {
+      @Override
+      public void onSelectionChange(SelectionChangeEvent event) {
+        label.setText("Selected "
+            + selectionModel.getSelectedSet().toString());
+      }
+    });
+
+    StandardTreeView stree = new StandardTreeView(new MyTreeViewModel(
+        selectionModel), "...");
+    stree.setSelectionModel(selectionModel);
+    stree.setAnimationEnabled(true);
+
+    p.add(stree);
+    p.add(new HTML("<hr>"));
+    p.add(label);
+
+    return p;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Category.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Category.java
new file mode 100644
index 0000000..d8089b3
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Category.java
@@ -0,0 +1,50 @@
+/*
+ * 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.sample.bikeshed.cookbook.client;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A category of recipes.
+ */
+public class Category {
+  private final String title;
+  private final Recipe[] recipes;
+
+  public Category(String title, Recipe[] recipes) {
+    this.title = title;
+    this.recipes = recipes;
+  }
+
+  /**
+   * Gets the recipes in this category.
+   * 
+   * @return this category's recipes
+   */
+  public List<Recipe> getRecipes() {
+    return Arrays.asList(recipes);
+  }
+
+  /**
+   * Gets this category's title.
+   * 
+   * @return the category title
+   */
+  public String getTitle() {
+    return title;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Cookbook.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Cookbook.java
new file mode 100644
index 0000000..73abf66
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Cookbook.java
@@ -0,0 +1,148 @@
+/*
+ * 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.sample.bikeshed.cookbook.client;
+
+import com.google.gwt.bikeshed.cells.client.Cell;
+import com.google.gwt.bikeshed.list.shared.ListListModel;
+import com.google.gwt.bikeshed.list.shared.SelectionModel;
+import com.google.gwt.bikeshed.list.shared.SelectionModel.SelectionChangeEvent;
+import com.google.gwt.bikeshed.tree.client.StandardTreeView;
+import com.google.gwt.bikeshed.tree.client.TreeNode;
+import com.google.gwt.bikeshed.tree.client.TreeViewModel;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiFactory;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.DockLayoutPanel;
+import com.google.gwt.user.client.ui.RootLayoutPanel;
+import com.google.gwt.user.client.ui.Widget;
+
+import java.util.List;
+
+/**
+ * Cookbook sample.
+ */
+public class Cookbook implements EntryPoint {
+
+  interface Binder extends UiBinder<Widget, Cookbook> {}
+
+  static class CategoryCell extends Cell<Category, Void> {
+    @Override
+    public void render(Category value, Void viewData, StringBuilder sb) {
+      sb.append(value.getTitle());
+    }
+  }
+
+  static class RecipeCell extends Cell<Recipe, Void> {
+    @Override
+    public void render(Recipe value, Void viewData, StringBuilder sb) {
+      sb.append(value.getTitle());
+    }
+  }
+
+  private final class RecipeTreeModel implements TreeViewModel {
+    private ListListModel<Category> catModel = new ListListModel<Category>();
+
+    @Override
+    public <T> NodeInfo<?> getNodeInfo(T value, TreeNode<T> treeNode) {
+      if (value == null) {
+        // Categories at the root.
+        return new DefaultNodeInfo<Category>(catModel, new CategoryCell());
+      } else if (value instanceof Category) {
+        // Demos for each category.
+        Category category = (Category) value;
+        return new DefaultNodeInfo<Recipe>(new ListListModel<Recipe>(
+            category.getRecipes()), new RecipeCell());
+      }
+      return null;
+    }
+
+    @Override
+    public boolean isLeaf(Object value, TreeNode<?> treeNode) {
+      // The root and categories have children.
+      if (value == null || value instanceof Category) {
+        return false;
+      }
+
+      // Demos do not.
+      return true;
+    }
+  }
+
+  private static final Binder binder = GWT.create(Binder.class);
+
+  @UiField DockLayoutPanel dock;
+  @UiField StandardTreeView recipeTree;
+
+  private RecipeTreeModel recipeTreeModel = new RecipeTreeModel();
+  private SingleSelectionModel<Object> treeSelection;
+  private SimpleCellListRecipe defaultRecipe;
+  private Recipe curRecipe;
+
+  @Override
+  public void onModuleLoad() {
+    RootLayoutPanel.get().add(binder.createAndBindUi(this));
+    createRecipes(recipeTreeModel.catModel.getList());
+
+    treeSelection = new SingleSelectionModel<Object>();
+    recipeTree.setSelectionModel(treeSelection);
+    treeSelection.addSelectionChangeHandler(new SelectionModel.SelectionChangeHandler() {
+      @Override
+      public void onSelectionChange(SelectionChangeEvent event) {
+        Object o = treeSelection.getSelectedObject();
+        if (o instanceof Recipe) {
+          showRecipe((Recipe) o);
+        }
+      }
+    });
+
+    showRecipe(defaultRecipe);
+  }
+
+  @UiFactory
+  StandardTreeView createTreeView() {
+    return new StandardTreeView(recipeTreeModel, null);
+  }
+
+  private void createRecipes(List<Category> cats) {
+    defaultRecipe = new SimpleCellListRecipe();
+
+    cats.add(new Category("Lists", new Recipe[] {
+        defaultRecipe
+    }));
+    cats.add(new Category("Tables", new Recipe[] {
+        new BasicTableRecipe(),
+        new EditableTableRecipe(),
+    }));
+    cats.add(new Category("Trees", new Recipe[] {
+        new BasicTreeRecipe(),
+        new SideBySideTreeRecipe(),
+    }));
+    cats.add(new Category("Other", new Recipe[] {
+        new ValidationRecipe(),
+        new MailRecipe(),
+    }));
+  }
+
+  private void showRecipe(Recipe recipe) {
+    if (curRecipe != null) {
+      dock.remove(curRecipe.getWidget());
+    }
+    dock.add(recipe.getWidget());
+    curRecipe = recipe;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Cookbook.ui.xml b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Cookbook.ui.xml
new file mode 100644
index 0000000..0ca6e08
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Cookbook.ui.xml
@@ -0,0 +1,16 @@
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+	xmlns:g='urn:import:com.google.gwt.user.client.ui'
+	xmlns:l='urn:import:com.google.gwt.bikeshed.list.client'
+	xmlns:t='urn:import:com.google.gwt.bikeshed.tree.client'>
+
+	<ui:style field='common' src='common.css' />
+
+	<g:DockLayoutPanel unit='EM' ui:field='dock'>
+		<g:north size="2">
+			<g:HTML>Table Sample</g:HTML>
+		</g:north>
+		<g:west size="16">
+			<t:StandardTreeView ui:field='recipeTree'/>
+		</g:west>
+	</g:DockLayoutPanel>
+</ui:UiBinder>
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/EditableTableRecipe.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/EditableTableRecipe.java
new file mode 100644
index 0000000..1307d2a
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/EditableTableRecipe.java
@@ -0,0 +1,116 @@
+/*
+ * 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.sample.bikeshed.cookbook.client;
+
+import com.google.gwt.bikeshed.cells.client.EditTextCell;
+import com.google.gwt.bikeshed.cells.client.FieldUpdater;
+import com.google.gwt.bikeshed.cells.client.TextCell;
+import com.google.gwt.bikeshed.list.client.Column;
+import com.google.gwt.bikeshed.list.client.Header;
+import com.google.gwt.bikeshed.list.client.PagingTableListView;
+import com.google.gwt.bikeshed.list.shared.ListListModel;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Widget;
+
+import java.util.List;
+
+/**
+ * Editable table recipe.
+ */
+public class EditableTableRecipe extends Recipe {
+
+  private static class EditTextColumn extends Column<String, String, String> {
+    public EditTextColumn() {
+      super(new EditTextCell());
+    }
+
+    @Override
+    public String getValue(String object) {
+      return object;
+    }
+  }
+
+  public EditableTableRecipe() {
+    super("Editable Table");
+  }
+
+  @Override
+  protected Widget createWidget() {
+    final ListListModel<String> model = new ListListModel<String>();
+    final PagingTableListView<String> table = new PagingTableListView<String>(model, 10);
+
+    for (int i = 0; i < 25; ++i) {
+      model.getList().add("" + i);
+    }
+
+    EditTextColumn column = new EditTextColumn();
+    Header<String> header = new Header<String>(TextCell.getInstance());
+    header.setValue("<b>item</b>");
+    table.addColumn(column, header);
+
+    column.setFieldUpdater(new FieldUpdater<String, String, String>() {
+      @Override
+      public void update(int index, String object, String value, String viewData) {
+        model.getList().set(index, value);
+      }
+    });
+
+    FlowPanel plusMinusPanel = new FlowPanel();
+    Button addBtn = new Button("+", new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        List<String> list = model.getList();
+        list.add("" + list.size());
+      }
+    });
+    Button removeBtn = new Button("-", new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        int size = model.getList().size();
+        if (size > 0) {
+          model.getList().remove(size - 1);
+        }
+      }
+    });
+    plusMinusPanel.add(addBtn);
+    plusMinusPanel.add(removeBtn);
+
+    FlowPanel nextPrevPanel = new FlowPanel();
+    Button prevBtn = new Button("<", new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        table.previousPage();
+      }
+    });
+    Button nextBtn = new Button(">", new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        table.nextPage();
+      }
+    });
+    nextPrevPanel.add(prevBtn);
+    nextPrevPanel.add(nextBtn);
+
+    FlowPanel fp = new FlowPanel();
+    fp.add(table);
+    fp.add(nextPrevPanel);
+    fp.add(plusMinusPanel);
+    return fp;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/mail/client/MailSample.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MailRecipe.java
similarity index 88%
rename from bikeshed/src/com/google/gwt/sample/bikeshed/mail/client/MailSample.java
rename to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MailRecipe.java
index d4d9cea..02aa427 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/mail/client/MailSample.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MailRecipe.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.mail.client;
+package com.google.gwt.sample.bikeshed.cookbook.client;
 
 import com.google.gwt.bikeshed.cells.client.ButtonCell;
 import com.google.gwt.bikeshed.cells.client.CheckboxCell;
@@ -23,18 +23,17 @@
 import com.google.gwt.bikeshed.list.client.TextColumn;
 import com.google.gwt.bikeshed.list.shared.DefaultSelectionModel;
 import com.google.gwt.bikeshed.list.shared.ListListModel;
-import com.google.gwt.bikeshed.list.shared.ProvidesKey;
-import com.google.gwt.core.client.EntryPoint;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyUpEvent;
 import com.google.gwt.event.dom.client.KeyUpHandler;
 import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.HorizontalPanel;
 import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.RootPanel;
 import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.Widget;
 
 import java.util.HashMap;
 import java.util.List;
@@ -43,9 +42,9 @@
 import java.util.TreeMap;
 
 /**
- * A demo of selection features.
+ * A recipe for mail-like selection features.
  */
-public class MailSample implements EntryPoint, ClickHandler {
+public class MailRecipe extends Recipe implements ClickHandler {
 
   static class MailSelectionModel extends DefaultSelectionModel<Message> {
     enum Type {
@@ -56,13 +55,6 @@
       }
     }
 
-    private static ProvidesKey<Message> keyProvider =
-      new ProvidesKey<Message>() {
-        public Object getKey(Message item) {
-          return Integer.valueOf(item.id);
-        }
-    };
-
     // A map from enum names to their values
     private static Map<String, Type> typeMap = new HashMap<String, Type>();
 
@@ -70,11 +62,6 @@
     private Type type = Type.NONE;
 
     @Override
-    public ProvidesKey<Message> getKeyProvider() {
-      return keyProvider;
-    }
-
-    @Override
     public boolean isDefaultSelected(Message object) {
       switch (type) {
         case NONE:
@@ -131,6 +118,7 @@
       return sb.toString();
     }
 
+    @Override
     protected void scheduleSelectionChangeEvent() {
       selectionLabel.setText("Selected " + this.toString());
       super.scheduleSelectionChangeEvent();
@@ -236,6 +224,10 @@
 
   private PagingTableListView<Message> table;
 
+  public MailRecipe() {
+    super("Mail");
+  }
+
   // Handle events for all buttons here in order to avoid creating multiple
   // ClickHandlers
   public void onClick(ClickEvent event) {
@@ -251,7 +243,8 @@
     }
   }
 
-  public void onModuleLoad() {
+  @Override
+  protected Widget createWidget() {
     ListListModel<Message> listModel = new ListListModel<Message>();
     List<Message> messages = listModel.getList();
     Random rand = new Random();
@@ -294,7 +287,7 @@
       }
     };
     table.addColumn(idColumn, "ID");
-
+  
     TextColumn<Message> isReadColumn = new TextColumn<Message>() {
       @Override
       public String getValue(Message object) {
@@ -346,19 +339,21 @@
     panel.add(searchLabel);
     panel.add(searchBox);
 
-    RootPanel.get().add(panel);
-    RootPanel.get().add(makeButton("Search Subject", "SUBJECT"));
-    RootPanel.get().add(makeButton("Search Senders", "SENDER"));
-    RootPanel.get().add(new HTML("<br>"));
-    RootPanel.get().add(table);
-    RootPanel.get().add(new HTML("<br>"));
-    RootPanel.get().add(makeButton("Select None", "NONE"));
-    RootPanel.get().add(makeButton("Select All On This Page", "PAGE"));
-    RootPanel.get().add(makeButton("Select All", "ALL"));
-    RootPanel.get().add(makeButton("Select Read", "READ"));
-    RootPanel.get().add(makeButton("Select Unread", "UNREAD"));
-    RootPanel.get().add(new HTML("<hr>"));
-    RootPanel.get().add(selectionLabel);
+    FlowPanel p = new FlowPanel();
+    p.add(panel);
+    p.add(makeButton("Search Subject", "SUBJECT"));
+    p.add(makeButton("Search Senders", "SENDER"));
+    p.add(new HTML("<br>"));
+    p.add(table);
+    p.add(new HTML("<br>"));
+    p.add(makeButton("Select None", "NONE"));
+    p.add(makeButton("Select All On This Page", "PAGE"));
+    p.add(makeButton("Select All", "ALL"));
+    p.add(makeButton("Select Read", "READ"));
+    p.add(makeButton("Select Unread", "UNREAD"));
+    p.add(new HTML("<hr>"));
+    p.add(selectionLabel);
+    return p;
   }
 
   private Button makeButton(String label, String id) {
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MultiSelectionModel.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MultiSelectionModel.java
new file mode 100644
index 0000000..7b63ecd
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MultiSelectionModel.java
@@ -0,0 +1,47 @@
+/*
+ * 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.sample.bikeshed.cookbook.client;
+
+import com.google.gwt.bikeshed.list.shared.SelectionModel.AbstractSelectionModel;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * A simple selection model that allows only multiple objects to be selected.
+ */
+public class MultiSelectionModel<T> extends AbstractSelectionModel<T> {
+
+  private Set<T> selectedSet = new TreeSet<T>();
+
+  public boolean isSelected(T object) {
+    return selectedSet.contains(object);
+  }
+
+  @Override
+  public void setSelected(T object, boolean selected) {
+    if (selected) {
+      selectedSet.add(object);
+    } else {
+      selectedSet.remove(object);
+    }
+    scheduleSelectionChangeEvent();
+  }
+
+  public Set<T> getSelectedSet() {
+    return selectedSet;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/MyTreeViewModel.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MyTreeViewModel.java
similarity index 98%
rename from bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/MyTreeViewModel.java
rename to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MyTreeViewModel.java
index eb8623d..127e446 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/MyTreeViewModel.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MyTreeViewModel.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.tree.client;
+package com.google.gwt.sample.bikeshed.cookbook.client;
 
 import com.google.gwt.bikeshed.cells.client.ButtonCell;
 import com.google.gwt.bikeshed.cells.client.Cell;
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Recipe.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Recipe.java
new file mode 100644
index 0000000..cf66a1b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Recipe.java
@@ -0,0 +1,43 @@
+/*
+ * 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.sample.bikeshed.cookbook.client;
+
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Abstract base class for all recipes.
+ */
+public abstract class Recipe {
+  private final String title;
+  private Widget widget;
+
+  public Recipe(String title) {
+    this.title = title;
+  }
+
+  public final Widget getWidget() {
+    if (widget == null) {
+      widget = createWidget();
+    }
+    return widget;
+  }
+
+  public String getTitle() {
+    return title;
+  }
+
+  protected abstract Widget createWidget();
+}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/SideBySideTreeRecipe.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/SideBySideTreeRecipe.java
new file mode 100644
index 0000000..497d503
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/SideBySideTreeRecipe.java
@@ -0,0 +1,59 @@
+/*
+ * 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.sample.bikeshed.cookbook.client;
+
+import com.google.gwt.bikeshed.list.shared.SelectionModel;
+import com.google.gwt.bikeshed.list.shared.SelectionModel.SelectionChangeEvent;
+import com.google.gwt.bikeshed.tree.client.SideBySideTreeView;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * SideBySideTree Recipe.
+ */
+public class SideBySideTreeRecipe extends Recipe {
+
+  public SideBySideTreeRecipe() {
+    super("Side-by-side Tree");
+  }
+
+  @Override
+  protected Widget createWidget() {
+    FlowPanel p = new FlowPanel();
+
+    final Label label = new Label();
+    final MultiSelectionModel<Object> selectionModel = new MultiSelectionModel<Object>();
+    selectionModel.addSelectionChangeHandler(new SelectionModel.SelectionChangeHandler() {
+      @Override
+      public void onSelectionChange(SelectionChangeEvent event) {
+        label.setText("Selected " + selectionModel.getSelectedSet().toString());
+      }
+    });
+
+    SideBySideTreeView sstree = new SideBySideTreeView(new MyTreeViewModel(
+        selectionModel), "...", 100, 4);
+    sstree.setSelectionModel(selectionModel);
+    sstree.setHeight("200px");
+
+    p.add(sstree);
+    p.add(new HTML("<hr>"));
+    p.add(label);
+
+    return p;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/simplecelllist/client/SimpleCellListSample.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/SimpleCellListRecipe.java
similarity index 81%
rename from bikeshed/src/com/google/gwt/sample/bikeshed/simplecelllist/client/SimpleCellListSample.java
rename to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/SimpleCellListRecipe.java
index 6f5bd0f..4184971 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/simplecelllist/client/SimpleCellListSample.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/SimpleCellListRecipe.java
@@ -13,23 +13,27 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.simplecelllist.client;
+package com.google.gwt.sample.bikeshed.cookbook.client;
 
 import com.google.gwt.bikeshed.cells.client.TextCell;
 import com.google.gwt.bikeshed.list.client.SimpleCellList;
 import com.google.gwt.bikeshed.list.shared.ListListModel;
-import com.google.gwt.core.client.EntryPoint;
 import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.Widget;
 
 import java.util.List;
 
 /**
- * SimpleCellList demo.
+ * SimpleCellList Recipe.
  */
-public class SimpleCellListSample implements EntryPoint {
+public class SimpleCellListRecipe extends Recipe {
 
-  public void onModuleLoad() {
+  public SimpleCellListRecipe() {
+    super("Simple Cell List");
+  }
+
+  @Override
+  protected Widget createWidget() {
     ListListModel<String> listModel = new ListListModel<String>();
     final List<String> list = listModel.getList();
     for (int i = 0; i < 50; i++) {
@@ -39,8 +43,6 @@
     SimpleCellList<String> simpleCellList =
       new SimpleCellList<String>(listModel, TextCell.getInstance(), 10, 5);
 
-    RootPanel.get().add(simpleCellList);
-
     new Timer() {
       int index = 0;
 
@@ -52,5 +54,7 @@
           schedule(100);
       }
     }.schedule(100);
+
+    return simpleCellList;
   }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/SingleSelectionModel.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/SingleSelectionModel.java
new file mode 100644
index 0000000..1d15171
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/SingleSelectionModel.java
@@ -0,0 +1,48 @@
+/*
+ * 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.sample.bikeshed.cookbook.client;
+
+import com.google.gwt.bikeshed.list.shared.SelectionModel.AbstractSelectionModel;
+
+/**
+ * A simple selection model that allows only one object to be selected a a time.
+ */
+public final class SingleSelectionModel<T> extends AbstractSelectionModel<T> {
+
+  private T curSelection;
+
+  @Override
+  public boolean isSelected(T object) {
+    return object.equals(curSelection);
+  }
+
+  @Override
+  public void setSelected(T object, boolean selected) {
+    if (selected) {
+      curSelection = object;
+    } else if (object.equals(curSelection)) {
+      curSelection = null;
+    }
+    scheduleSelectionChangeEvent();
+  }
+
+  /**
+   * Gets the currently-selected object.
+   */
+  public T getSelectedObject() {
+    return curSelection;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeService.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/TreeService.java
similarity index 94%
rename from bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeService.java
rename to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/TreeService.java
index 8b245bf..b157d08 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeService.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/TreeService.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.tree.client;
+package com.google.gwt.sample.bikeshed.cookbook.client;
 
 import com.google.gwt.user.client.rpc.RemoteService;
 import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeServiceAsync.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/TreeServiceAsync.java
similarity index 93%
rename from bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeServiceAsync.java
rename to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/TreeServiceAsync.java
index 211d5b2..c63b641 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeServiceAsync.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/TreeServiceAsync.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.tree.client;
+package com.google.gwt.sample.bikeshed.cookbook.client;
 
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/validation/client/ValidatableField.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidatableField.java
similarity index 96%
rename from bikeshed/src/com/google/gwt/sample/bikeshed/validation/client/ValidatableField.java
rename to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidatableField.java
index bd59e94..2ec9a3f 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/validation/client/ValidatableField.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidatableField.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.validation.client;
+package com.google.gwt.sample.bikeshed.cookbook.client;
 
 /**
  * A field with a pending value and an 'is invalid' flag.
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/validation/client/ValidatableInputCell.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidatableInputCell.java
similarity index 94%
rename from bikeshed/src/com/google/gwt/sample/bikeshed/validation/client/ValidatableInputCell.java
rename to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidatableInputCell.java
index 99e5f77..226be67 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/validation/client/ValidatableInputCell.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidatableInputCell.java
@@ -13,14 +13,14 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.validation.client;
+package com.google.gwt.sample.bikeshed.cookbook.client;
 
 import com.google.gwt.bikeshed.cells.client.Cell;
 import com.google.gwt.bikeshed.cells.client.ValueUpdater;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.InputElement;
 import com.google.gwt.dom.client.NativeEvent;
-import com.google.gwt.sample.bikeshed.validation.client.ValidatableField.DefaultValidatableField;
+import com.google.gwt.sample.bikeshed.cookbook.client.ValidatableField.DefaultValidatableField;
 
 /**
  * A String {@link Cell} that supports validation using a
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/validation/client/Validation.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidationRecipe.java
similarity index 91%
rename from bikeshed/src/com/google/gwt/sample/bikeshed/validation/client/Validation.java
rename to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidationRecipe.java
index dbe519c..cf0d4eb 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/validation/client/Validation.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidationRecipe.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.validation.client;
+package com.google.gwt.sample.bikeshed.cookbook.client;
 
 import com.google.gwt.bikeshed.cells.client.FieldUpdater;
 import com.google.gwt.bikeshed.list.client.Column;
@@ -21,16 +21,15 @@
 import com.google.gwt.bikeshed.list.client.TextColumn;
 import com.google.gwt.bikeshed.list.shared.ListListModel;
 import com.google.gwt.bikeshed.list.shared.ProvidesKey;
-import com.google.gwt.core.client.EntryPoint;
 import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.Widget;
 
 import java.util.List;
 
 /**
  * Validation demo.
  */
-public class Validation implements EntryPoint {
+public class ValidationRecipe extends Recipe {
 
   static class Address {
     static int genkey = 0;
@@ -69,7 +68,12 @@
     return zip % 3 == 0;
   }
 
-  public void onModuleLoad() {
+  public ValidationRecipe() {
+    super("Validation");
+  }
+
+  @Override
+  protected Widget createWidget() {
     ListListModel<Address> listModel = new ListListModel<Address>();
     final List<Address> list = listModel.getList();
     for (int i = 10; i < 50; i++) {
@@ -113,7 +117,7 @@
             String pendingValue = viewData.getValue();
 
             int zip = Integer.parseInt(pendingValue);
-            boolean zipInvalid = Validation.zipInvalid(zip);
+            boolean zipInvalid = ValidationRecipe.zipInvalid(zip);
 
             final Address newValue = new Address(object);
             newValue.zip = pendingValue == null ? value : pendingValue;
@@ -141,6 +145,6 @@
     table.addColumn(zipColumn);
     table.addColumn(messageColumn);
 
-    RootPanel.get().add(table);
+    return table;
   }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/common.css b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/common.css
new file mode 100644
index 0000000..93aa1c2
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/common.css
@@ -0,0 +1,49 @@
+.bg {
+  border: 8px solid white;
+  border-right: 12px solid white;
+  border-bottom: 14px solid white;
+  -webkit-border-image: url(border.png) 8 12 14 8 round round;
+  -moz-border-image: url(border.png) 8 12 14 8 round round;
+}
+
+.header {
+  font-weight: light;
+  font-size: 12pt;
+  text-align: center;
+  margin-bottom: 0.5em;
+}
+
+.header-left {
+  font-weight: light;
+  font-size: 12pt;
+  margin-bottom: 0.5em;
+}
+
+.header-main {
+  font-weight: light;
+  font-size: 18pt;
+}
+
+.table {
+  width: 95%;
+  font-size: 8pt;
+  border-spacing: 0px 0px;
+  border-collapse: collapse;
+}
+
+.table th {
+  border-bottom: 1px solid #ccc;
+}
+
+.table td {
+  border-left: 1px solid #ccc;
+  border-right: 1px solid #ccc;
+}
+
+.table tfoot th {
+  border-width: 0px;
+}
+
+.padded {
+  padding: 5px;
+}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/server/Dictionary.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/server/Dictionary.java
similarity index 99%
rename from bikeshed/src/com/google/gwt/sample/bikeshed/tree/server/Dictionary.java
rename to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/server/Dictionary.java
index 233d2f3..8f339a6 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/server/Dictionary.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/server/Dictionary.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.tree.server;
+package com.google.gwt.sample.bikeshed.cookbook.server;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/server/TreeServiceImpl.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/server/TreeServiceImpl.java
similarity index 88%
rename from bikeshed/src/com/google/gwt/sample/bikeshed/tree/server/TreeServiceImpl.java
rename to bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/server/TreeServiceImpl.java
index de18642..ebca7ec 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/server/TreeServiceImpl.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/server/TreeServiceImpl.java
@@ -13,9 +13,9 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.bikeshed.tree.server;
+package com.google.gwt.sample.bikeshed.cookbook.server;
 
-import com.google.gwt.sample.bikeshed.tree.client.TreeService;
+import com.google.gwt.sample.bikeshed.cookbook.client.TreeService;
 import com.google.gwt.user.server.rpc.RemoteServiceServlet;
 
 import java.util.List;
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/mail/MailSample.gwt.xml b/bikeshed/src/com/google/gwt/sample/bikeshed/mail/MailSample.gwt.xml
deleted file mode 100644
index eaf5297..0000000
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/mail/MailSample.gwt.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 0.0.999//EN" "http://google-web-toolkit.googlecode.com/svn/tags/0.0.999/distro-source/core/src/gwt-module.dtd">
-<module rename-to='mailsample'>
-  <!-- Inherit the core Web Toolkit stuff.                        -->
-  <inherits name='com.google.gwt.user.User'/>
-  <inherits name='com.google.gwt.bikeshed.list.List'/>
-  <inherits name='com.google.gwt.bikeshed.tree.Tree'/>
-
-  <!-- Inherit the default GWT style sheet.  You can change       -->
-  <!-- the theme of your GWT application by uncommenting          -->
-  <!-- any one of the following lines.                            -->
-  <inherits name='com.google.gwt.user.theme.standard.Standard'/>
-  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
-  <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->
-
-  <!-- Other module inherits                                      -->
-
-  <!-- Specify the app entry point class.                         -->
-  <entry-point class='com.google.gwt.sample.bikeshed.mail.client.MailSample'/>
-
-  <!-- Specify the paths for translatable code                    -->
-  <source path='client'/>
-  <source path='shared'/>
-
-</module>
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/simplecelllist/SimpleCellList.gwt.xml b/bikeshed/src/com/google/gwt/sample/bikeshed/simplecelllist/SimpleCellList.gwt.xml
deleted file mode 100644
index 9ac9c97..0000000
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/simplecelllist/SimpleCellList.gwt.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Could not determine the version of your GWT SDK; using the module DTD from GWT 1.6.4. You may want to change this. -->
-<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6.4//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.6.4/distro-source/core/src/gwt-module.dtd">
-<module rename-to='simplecelllist'>
-	<inherits name="com.google.gwt.bikeshed.list.List" />
-	<source path="client" />
-	<entry-point
-		class="com.google.gwt.sample.bikeshed.simplecelllist.client.SimpleCellListSample">
-	</entry-point>
-</module>
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/TreeSample.gwt.xml b/bikeshed/src/com/google/gwt/sample/bikeshed/tree/TreeSample.gwt.xml
deleted file mode 100644
index c757db5..0000000
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/TreeSample.gwt.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 0.0.999//EN" "http://google-web-toolkit.googlecode.com/svn/tags/0.0.999/distro-source/core/src/gwt-module.dtd">
-<module rename-to='treesample'>
-  <!-- Inherit the core Web Toolkit stuff.                        -->
-  <inherits name='com.google.gwt.user.User'/>
-  <inherits name='com.google.gwt.bikeshed.list.List'/>
-  <inherits name='com.google.gwt.bikeshed.tree.Tree'/>
-
-  <!-- Inherit the default GWT style sheet.  You can change       -->
-  <!-- the theme of your GWT application by uncommenting          -->
-  <!-- any one of the following lines.                            -->
-  <inherits name='com.google.gwt.user.theme.standard.Standard'/>
-  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
-  <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->
-
-  <!-- Other module inherits                                      -->
-
-  <!-- Specify the app entry point class.                         -->
-  <entry-point class='com.google.gwt.sample.bikeshed.tree.client.TreeSample'/>
-
-  <!-- Specify the paths for translatable code                    -->
-  <source path='client'/>
-  <source path='shared'/>
-
-</module>
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeSample.java b/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeSample.java
deleted file mode 100644
index 8f88176..0000000
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/tree/client/TreeSample.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.sample.bikeshed.tree.client;
-
-import com.google.gwt.bikeshed.list.shared.SelectionModel.AbstractSelectionModel;
-import com.google.gwt.bikeshed.tree.client.SideBySideTreeView;
-import com.google.gwt.bikeshed.tree.client.StandardTreeView;
-import com.google.gwt.core.client.EntryPoint;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.RootPanel;
-
-import java.util.Set;
-import java.util.TreeSet;
-
-/**
- * A demo of the asynchronous Tree model.
- */
-public class TreeSample implements EntryPoint {
-
-  class MySelectionModel extends AbstractSelectionModel<Object> {
-
-    private Label label;
-    private Set<Object> selectedSet = new TreeSet<Object>();
-
-    public MySelectionModel(Label label) {
-      this.label = label;
-    }
-
-    public boolean isSelected(Object object) {
-      return selectedSet.contains(object);
-    }
-
-    public void setSelected(Object object, boolean selected) {
-      if (selected) {
-        selectedSet.add(object);
-      } else {
-        selectedSet.remove(object);
-      }
-      label.setText("Selected " + selectedSet.toString());
-      scheduleSelectionChangeEvent();
-    }
-  }
-
-  public void onModuleLoad() {
-    Label label1 = new Label();
-    MySelectionModel selectionModel1 = new MySelectionModel(label1);
-
-    StandardTreeView stree = new StandardTreeView(new MyTreeViewModel(
-        selectionModel1), "...");
-    stree.setSelectionModel(selectionModel1);
-    stree.setAnimationEnabled(true);
-
-    RootPanel.get().add(stree);
-    RootPanel.get().add(new HTML("<hr>"));
-    RootPanel.get().add(label1);
-    RootPanel.get().add(new HTML("<hr>"));
-
-    Label label2 = new Label();
-    MySelectionModel selectionModel2 = new MySelectionModel(label2);
-    SideBySideTreeView sstree = new SideBySideTreeView(new MyTreeViewModel(
-        selectionModel2), "...", 100, 4);
-    sstree.setSelectionModel(selectionModel2);
-    sstree.setHeight("200px");
-
-    RootPanel.get().add(sstree);
-    RootPanel.get().add(new HTML("<hr>"));
-    RootPanel.get().add(label2);
-    RootPanel.get().add(new HTML("<hr>"));
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/validation/Validation.gwt.xml b/bikeshed/src/com/google/gwt/sample/bikeshed/validation/Validation.gwt.xml
deleted file mode 100644
index e422947..0000000
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/validation/Validation.gwt.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Could not determine the version of your GWT SDK; using the module DTD from GWT 1.6.4. You may want to change this. -->
-<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6.4//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.6.4/distro-source/core/src/gwt-module.dtd">
-<module rename-to='validation'>
-	<inherits name="com.google.gwt.bikeshed.list.List" />
-	<source path="client" />
-	<entry-point
-		class="com.google.gwt.sample.bikeshed.validation.client.Validation">
-	</entry-point>
-</module>
diff --git a/bikeshed/war/Mail.css b/bikeshed/war/Cookbook.css
similarity index 100%
rename from bikeshed/war/Mail.css
rename to bikeshed/war/Cookbook.css
diff --git a/bikeshed/war/Tree.html b/bikeshed/war/Cookbook.html
similarity index 74%
rename from bikeshed/war/Tree.html
rename to bikeshed/war/Cookbook.html
index 17a1984..e5a4ab9 100644
--- a/bikeshed/war/Tree.html
+++ b/bikeshed/war/Cookbook.html
@@ -2,9 +2,9 @@
 <html>
   <head>
     <meta http-equiv="content-type" content="text/html; charset=UTF-8">
-    <link type="text/css" rel="stylesheet" href="Tree.css">
-    <title>Tree Sample</title>
-    <script type="text/javascript" language="javascript" src="tree/tree.nocache.js"></script>
+    <link type="text/css" rel="stylesheet" href="Cookbook.css">
+    <title>Cookbook</title>
+    <script type="text/javascript" language="javascript" src="cookbook/cookbook.nocache.js"></script>
   </head>
 
   <body>
@@ -15,7 +15,5 @@
         in order for this application to display correctly.
       </div>
     </noscript>
-
-    <h1>Tree Sample</h1>
   </body>
 </html>
diff --git a/bikeshed/war/Mail.html b/bikeshed/war/Mail.html
deleted file mode 100644
index ce279e6..0000000
--- a/bikeshed/war/Mail.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
-    <link type="text/css" rel="stylesheet" href="Mail.css">
-    <title>Mail Sample</title>
-    <script type="text/javascript" language="javascript" src="mailsample/mailsample.nocache.js"></script>
-  </head>
-
-  <body>
-    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
-    <noscript>
-      <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
-        Your web browser must have JavaScript enabled
-        in order for this application to display correctly.
-      </div>
-    </noscript>
-
-    <h1>Mail Sample</h1>
-  </body>
-</html>
diff --git a/bikeshed/war/SimpleCellList.html b/bikeshed/war/SimpleCellList.html
deleted file mode 100644
index 3119975..0000000
--- a/bikeshed/war/SimpleCellList.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
-    <title>Simple Cell List Demo</title>
-    <script type="text/javascript" language="javascript" src="simplecelllist/simplecelllist.nocache.js"></script>
-  </head>
-
-  <body>
-    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
-
-  </body>
-</html>
diff --git a/bikeshed/war/Tree.css b/bikeshed/war/Tree.css
deleted file mode 100644
index ccb77f0..0000000
--- a/bikeshed/war/Tree.css
+++ /dev/null
@@ -1,59 +0,0 @@
-/** Add css rules here for your application. */
-
-div.gwt-stree-selectedItem {
-  border-style: solid;
-}
-
-div.gwt-sstree-column {
-  overflow-y: scroll;
-  overflow-x: auto;
-  position: relative;
-}
-
-div.gwt-sstree {
-  border: 2px solid black;
-}
-
-div.gwt-sstree-selectedItem {
-  background-color: rgb(56, 117, 215);
-}
-
-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;
-  font-weight: bold;
-  color: #777777;
-  margin: 40px 0px 70px;
-  text-align: center;
-}
-
-.sendButton {
-  display: block;
-  font-size: 16pt;
-}
-
-/** Most GWT widgets already have a style name defined */
-.gwt-DialogBox {
-  width: 400px;
-}
-
-.dialogVPanel {
-  margin: 5px;
-}
-
-.serverResponseLabelError {
-  color: red;
-}
-
-/** Set ids using widget.getElement().setId("idOfElement") */
-#closeButton {
-  margin: 15px 6px 6px;
-}
diff --git a/bikeshed/war/Validation.html b/bikeshed/war/Validation.html
deleted file mode 100644
index 93317bf..0000000
--- a/bikeshed/war/Validation.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
-    <title>Validation</title>
-    <script type="text/javascript" language="javascript" src="validation/validation.nocache.js"></script>
-  </head>
-
-  <body>
-    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
-
-  </body>
-</html>
diff --git a/bikeshed/war/WEB-INF/appengine-web.xml b/bikeshed/war/WEB-INF/appengine-web.xml
index 99223a5..4b248dd 100644
--- a/bikeshed/war/WEB-INF/appengine-web.xml
+++ b/bikeshed/war/WEB-INF/appengine-web.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
-	<application></application>
+	<application>gwt-bikeshed</application>
 	<version>1</version>
 	
 	<!-- Configure java.util.logging -->
diff --git a/bikeshed/war/WEB-INF/web.xml b/bikeshed/war/WEB-INF/web.xml
index 17718a8..2a3f9e8 100644
--- a/bikeshed/war/WEB-INF/web.xml
+++ b/bikeshed/war/WEB-INF/web.xml
@@ -24,7 +24,7 @@
 
   <servlet>
     <servlet-name>treeServlet</servlet-name>
-    <servlet-class>com.google.gwt.sample.bikeshed.tree.server.TreeServiceImpl</servlet-class>
+    <servlet-class>com.google.gwt.sample.bikeshed.cookbook.server.TreeServiceImpl</servlet-class>
   </servlet>
 
   <servlet-mapping>
@@ -44,14 +44,9 @@
 
   <servlet-mapping>
     <servlet-name>treeServlet</servlet-name>
-    <url-pattern>/tree/tree</url-pattern>
+    <url-pattern>/cookbook/tree</url-pattern>
   </servlet-mapping>
 
-  <!-- Default page to serve -->
-  <welcome-file-list>
-    <welcome-file>Tree.html</welcome-file>
-  </welcome-file-list>
-
   <!-- Require login. -->
   <security-constraint>
     <web-resource-collection>