Lots of prettier styles for the stock sample.


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7704 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/src/com/google/gwt/bikeshed/cells/client/EllipsisCell.java b/bikeshed/src/com/google/gwt/bikeshed/cells/client/EllipsisCell.java
new file mode 100644
index 0000000..72e9039
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/bikeshed/cells/client/EllipsisCell.java
@@ -0,0 +1,26 @@
+/*
+ * 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.bikeshed.cells.client;
+
+public class EllipsisCell extends Cell<String> {
+
+  @Override
+  public void render(String value, StringBuilder sb) {
+    sb.append("<div style='overflow:hidden; white-space:nowrap; text-overflow:ellipsis;'>");
+    sb.append(value);
+    sb.append("</div>");
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/StockSample.gwt.xml b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/StockSample.gwt.xml
index b8af876..8500059 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/StockSample.gwt.xml
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/StockSample.gwt.xml
@@ -6,20 +6,10 @@
   <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.bikeshed.sample.stocks.client.StockSample'/>
 
   <!-- Specify the paths for translatable code                    -->
   <source path='client'/>
   <source path='shared'/>
-
 </module>
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/Columns.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/Columns.java
index 889fcfe..426d715 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/Columns.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/Columns.java
@@ -18,6 +18,7 @@
 import com.google.gwt.bikeshed.cells.client.ButtonCell;
 import com.google.gwt.bikeshed.cells.client.CheckboxCell;
 import com.google.gwt.bikeshed.cells.client.CurrencyCell;
+import com.google.gwt.bikeshed.cells.client.EllipsisCell;
 import com.google.gwt.bikeshed.cells.client.ProfitLossCell;
 import com.google.gwt.bikeshed.cells.client.TextCell;
 import com.google.gwt.bikeshed.list.client.Column;
@@ -62,7 +63,7 @@
   };
 
   static Column<StockQuote, String> nameColumn =
-    new Column<StockQuote, String>(new TextCell()) {
+    new Column<StockQuote, String>(new EllipsisCell()) {
     @Override
     protected String getValue(StockQuote object) {
       return object.getName();
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/FavoritesWidget.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/FavoritesWidget.java
new file mode 100644
index 0000000..afa4c3a
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/FavoritesWidget.java
@@ -0,0 +1,55 @@
+/*
+ * 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.bikeshed.sample.stocks.client;
+
+import com.google.gwt.bikeshed.list.client.PagingTableListView;
+import com.google.gwt.bikeshed.list.client.TextHeader;
+import com.google.gwt.bikeshed.list.shared.ListModel;
+import com.google.gwt.bikeshed.sample.stocks.shared.StockQuote;
+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.Composite;
+import com.google.gwt.user.client.ui.Widget;
+
+public class FavoritesWidget extends Composite {
+
+  interface Binder extends UiBinder<Widget, FavoritesWidget> { }
+  private static final Binder binder = GWT.create(Binder.class);
+
+  @UiField PagingTableListView<StockQuote> listView;
+
+  private final ListModel<StockQuote> model;
+
+  public FavoritesWidget(ListModel<StockQuote> model) {
+    this.model = model;
+    initWidget(binder.createAndBindUi(this));
+
+    listView.addColumn(Columns.tickerColumn, new TextHeader("ticker"));
+    listView.addColumn(Columns.priceColumn, new TextHeader("price"));
+    listView.addColumn(Columns.changeColumn, new TextHeader("change"));
+    listView.addColumn(Columns.sharesColumn, new TextHeader("shares"));
+    listView.addColumn(Columns.dollarsColumn, new TextHeader("value"));
+    listView.addColumn(Columns.buyColumn);
+    listView.addColumn(Columns.sellColumn);
+  }
+
+  @UiFactory
+  PagingTableListView<StockQuote> createListView() {
+    return new PagingTableListView<StockQuote>(model, 10);
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/FavoritesWidget.ui.xml b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/FavoritesWidget.ui.xml
new file mode 100644
index 0000000..1c43720
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/FavoritesWidget.ui.xml
@@ -0,0 +1,19 @@
+<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'
+  xmlns:s='urn:import:com.google.gwt.bikeshed.sample.stocks.client'>
+
+  <ui:style field='common' src='common.css'/>
+
+  <g:DockLayoutPanel unit='EM'>
+    <g:north size='2'>
+      <g:Label styleName='{common.header-left}'>Portfolio / Favorites</g:Label>
+    </g:north>
+
+    <g:center>
+      <l:PagingTableListView ui:field='listView' styleName='{common.table}'/>
+    </g:center>
+  </g:DockLayoutPanel>
+</ui:UiBinder>
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.java
index 3fb325e..83a52ff 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.java
@@ -19,57 +19,59 @@
 import com.google.gwt.bikeshed.list.client.TextHeader;
 import com.google.gwt.bikeshed.list.shared.ListModel;
 import com.google.gwt.bikeshed.sample.stocks.shared.StockQuote;
-import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.dom.client.KeyUpEvent;
 import com.google.gwt.event.dom.client.KeyUpHandler;
+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.Composite;
-import com.google.gwt.user.client.ui.DockLayoutPanel;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.ScrollPanel;
 import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.Widget;
 
 /**
  * A widget containing a search box and a results table.
  */
 public class StockQueryWidget extends Composite {
 
-  private final TextBox queryField = new TextBox();
-  private PagingTableListView<StockQuote> resultsTable;
+  interface Binder extends UiBinder<Widget, StockQueryWidget> { }
+  private static final Binder binder = GWT.create(Binder.class);
 
-  public StockQueryWidget(ListModel<StockQuote> searchListModel, final Updater updater) { 
-    // Create the results table.
-    resultsTable = new PagingTableListView<StockQuote>(searchListModel, 10);
-    resultsTable.addColumn(Columns.favoriteColumn);
-    resultsTable.addColumn(Columns.tickerColumn, new TextHeader("ticker"));
-    resultsTable.addColumn(Columns.nameColumn, new TextHeader("name"));
-    resultsTable.addColumn(Columns.priceColumn, new TextHeader("price"));
-    resultsTable.addColumn(Columns.buyColumn);
-   
+  @UiField TextBox queryField = new TextBox();
+  @UiField PagingTableListView<StockQuote> listView;
+
+  private final ListModel<StockQuote> model;
+
+  public StockQueryWidget(ListModel<StockQuote> model, final Updater updater) {
+    this.model = model;
+    initWidget(binder.createAndBindUi(this));
+
+    listView.addColumn(Columns.favoriteColumn);
+    listView.addColumn(Columns.tickerColumn, new TextHeader("ticker"));
+    listView.addColumn(Columns.nameColumn, new TextHeader("name"));
+    listView.addColumn(Columns.changeColumn, new TextHeader("change"));
+    listView.addColumn(Columns.priceColumn, new TextHeader("price"));
+    listView.addColumn(Columns.buyColumn);
+
     // Focus the cursor on the name field when the app loads
     queryField.setFocus(true);
     queryField.selectAll();
     queryField.setText("G");
-    
+
     // Add a handler to send the name to the server
     queryField.addKeyUpHandler(new KeyUpHandler() {
       public void onKeyUp(KeyUpEvent event) {
         updater.update();
       }
     });
-    
-    DockLayoutPanel layoutPanel = new DockLayoutPanel(Unit.EM);
-    
-    HorizontalPanel panel = new HorizontalPanel();
-    panel.add(new Label("Enter query: "));
-    panel.add(queryField);
-    layoutPanel.addNorth(panel, 2.0);
-    layoutPanel.add(new ScrollPanel(resultsTable));
-    
-    initWidget(layoutPanel);
   }
-  
+
   public String getSearchQuery() {
     return queryField.getText();
   }
+
+  @UiFactory
+  PagingTableListView<StockQuote> createListView() {
+    return new PagingTableListView<StockQuote>(model, 10);
+  }
 }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.ui.xml b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.ui.xml
new file mode 100644
index 0000000..9edb59b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.ui.xml
@@ -0,0 +1,19 @@
+<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'
+  xmlns:s='urn:import:com.google.gwt.bikeshed.sample.stocks.client'>
+
+  <ui:style field='common' src='common.css'/>
+
+  <g:DockLayoutPanel unit='EM'>
+    <g:north size='2'>
+      <g:HTMLPanel><span class='{common.header-left}'>Enter query:</span> <g:TextBox ui:field='queryField'/></g:HTMLPanel>
+    </g:north>
+
+    <g:center>
+      <l:PagingTableListView ui:field='listView' styleName='{common.table}'/>
+    </g:center>
+  </g:DockLayoutPanel>
+</ui:UiBinder>
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 ac2ed0f..41f7ef7 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
@@ -16,8 +16,6 @@
 package com.google.gwt.bikeshed.sample.stocks.client;
 
 import com.google.gwt.bikeshed.cells.client.FieldUpdater;
-import com.google.gwt.bikeshed.list.client.PagingTableListView;
-import com.google.gwt.bikeshed.list.client.TextHeader;
 import com.google.gwt.bikeshed.list.shared.AsyncListModel;
 import com.google.gwt.bikeshed.list.shared.ListListModel;
 import com.google.gwt.bikeshed.list.shared.Range;
@@ -32,21 +30,18 @@
 import com.google.gwt.bikeshed.tree.client.TreeNode;
 import com.google.gwt.core.client.EntryPoint;
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.event.logical.shared.CloseEvent;
 import com.google.gwt.event.logical.shared.CloseHandler;
 import com.google.gwt.i18n.client.NumberFormat;
+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.Timer;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.DockLayoutPanel;
-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.PopupPanel;
 import com.google.gwt.user.client.ui.RootLayoutPanel;
-import com.google.gwt.user.client.ui.ScrollPanel;
-import com.google.gwt.user.client.ui.VerticalPanel;
 import com.google.gwt.user.client.ui.Widget;
 
 import java.util.HashMap;
@@ -67,39 +62,31 @@
     return NumberFormat.getCurrencyFormat("USD").format(price / 100.0);
   }
 
+  private final StockServiceAsync dataService = GWT.create(StockService.class);
+
+  private Map<String, ListListModel<Transaction>> transactionListListModelsByTicker =
+    new HashMap<String, ListListModel<Transaction>>();
+  private List<Transaction> transactions;
+
+  private AsyncListModel<StockQuote> favoritesListModel;
+  private AsyncListModel<StockQuote> searchListModel;
+  private ListListModel<Transaction> transactionListModel;
+  private TransactionTreeViewModel treeModel;
+
+  interface Binder extends UiBinder<Widget, StockSample> { }
+  private static final Binder binder = GWT.create(Binder.class);
+
+  @UiField Label cashLabel;
+  @UiField Label netWorthLabel;
+  @UiField FavoritesWidget favoritesWidget;
+  @UiField StockQueryWidget queryWidget;
+  @UiField SideBySideTreeView transactionTree;
+
   /**
    * The popup used to purchase stock.
    */
   private BuySellPopup buySellPopup = new BuySellPopup();
 
-  private final Label cashLabel = new Label();
-
-  /**
-   * The {@link StockService} used to retrieve data.
-   */
-  private final StockServiceAsync dataService = GWT.create(StockService.class);
-
-  private AsyncListModel<StockQuote> favoritesListModel;
-
-  private PagingTableListView<StockQuote> favoritesTable;
-
-  private final Label netWorthLabel = new Label();
-
-  private StockQueryWidget queryWidget;
-
-  private AsyncListModel<StockQuote> searchListModel;
-
-  private Map<String, ListListModel<Transaction>> transactionListListModelsByTicker =
-    new HashMap<String, ListListModel<Transaction>>();
-
-  private ListListModel<Transaction> transactionListModel;
-
-  private List<Transaction> transactions;
-
-  private SideBySideTreeView transactionTree;
-
-  private TransactionTreeViewModel treeModel;
-
   /**
    * The timer used to update the stock quotes.
    */
@@ -114,8 +101,8 @@
    * This is the entry point method.
    */
   public void onModuleLoad() {
-
-    // Create the list models
+    // Create the various models. Do this before binding the UI, because some
+    // of the UiFactories need the models to instantiate their widgets.
     searchListModel = new AsyncListModel<StockQuote>(
         new DataSource<StockQuote>() {
           public void requestData(AsyncListModel<StockQuote> listModel) {
@@ -130,24 +117,16 @@
           }
         });
 
+    treeModel = new TransactionTreeViewModel(this,
+        favoritesListModel, transactionListListModelsByTicker);
+
     transactionListModel = new ListListModel<Transaction>();
     transactions = transactionListModel.getList();
 
-    // Create the favorites table.
-    favoritesTable = new PagingTableListView<StockQuote>(favoritesListModel, 10);
-    favoritesTable.addColumn(Columns.tickerColumn, new TextHeader("ticker"));
-    favoritesTable.addColumn(Columns.priceColumn, new TextHeader("price"));
-    favoritesTable.addColumn(Columns.changeColumn, new TextHeader("change"));
-    favoritesTable.addColumn(Columns.sharesColumn, new TextHeader("shares"));
-    favoritesTable.addColumn(Columns.dollarsColumn, new TextHeader("value"));
-    favoritesTable.addColumn(Columns.profitLossColumn, new TextHeader("profit"));
-    favoritesTable.addColumn(Columns.buyColumn);
-    favoritesTable.addColumn(Columns.sellColumn);
+    // Now create the UI.
+    RootLayoutPanel.get().add(binder.createAndBindUi(this));
 
-    treeModel = new TransactionTreeViewModel(this,
-        favoritesListModel, transactionListListModelsByTicker);
-    transactionTree = new SideBySideTreeView(treeModel, null, 200, 200);
-
+    // Hook up handlers to columns and the buy/sell popup.
     Columns.favoriteColumn.setFieldUpdater(new FieldUpdater<StockQuote, Boolean>() {
       public void update(StockQuote object, Boolean value) {
         setFavorite(object.getTicker(), value);
@@ -172,83 +151,48 @@
       public void onClose(CloseEvent<PopupPanel> event) {
         Transaction t = buySellPopup.getTransaction();
         if (t != null) {
-          dataService.transact(t, new AsyncCallback<Transaction>() {
-            public void onFailure(Throwable caught) {
-              Window.alert("Error: " + caught.getMessage());
-            }
-
-            public void onSuccess(Transaction result) {
-              recordTransaction(result);
-              update();
-            }
-
-            /**
-             * Update transactions (list of all transactions),
-             * transactionTickers (set of all tickers involved in
-             * transactions), and transactionsByTicker (map from
-             * ticker to lists of transactions for that ticker).
-             */
-            private void recordTransaction(Transaction result) {
-              transactions.add(0, result);
-              String ticker = result.getTicker();
-
-              // Update the next level of the transaction tree
-              // for the given ticker
-              ListListModel<Transaction> t =
-                transactionListListModelsByTicker.get(ticker);
-              if (t == null) {
-                t = new ListListModel<Transaction>();
-                transactionListListModelsByTicker.put(ticker, t);
-              }
-              t.getList().add(result);
-            }
-          });
-       }
+          transact(t);
+        }
       }
     });
 
-    // Add components to the page.
-
-    Widget headerWidget = new HTML("<b>Stock Game</b>");
-
-    HorizontalPanel cashPanel = new HorizontalPanel();
-    cashPanel.add(new HTML("<b>Available cash:</b>"));
-    cashPanel.add(cashLabel);
-    HorizontalPanel netWorthPanel = new HorizontalPanel();
-    netWorthPanel.add(new HTML("<b>Net worth:</b>"));
-    netWorthPanel.add(netWorthLabel);
-    VerticalPanel moneyPanel = new VerticalPanel();
-    moneyPanel.add(cashPanel);
-    moneyPanel.add(netWorthPanel);
-
-    DockLayoutPanel westPanel = new DockLayoutPanel(Unit.PCT);
-    westPanel.addNorth(moneyPanel, 25.0);
-    westPanel.add(new HTML("<table>" +
-        "<tr><td>Dan Rice</td><td>$10000</td></tr>" +
-        "<tr><td>Joel Webber</td><td>$10000</td></tr>" +
-        "<tr><td>John Labanca</td><td>$10000</td></tr>" +
-        "</table>"));
-
-    DockLayoutPanel layoutPanel = new DockLayoutPanel(Unit.EM);
-    layoutPanel.addNorth(headerWidget, 4.0);
-    layoutPanel.addWest(westPanel, 15.0);
-    layoutPanel.addNorth(transactionTree, 18.0);
-
-    DockLayoutPanel innerLayoutPanel = new DockLayoutPanel(Unit.PCT);
-    this.queryWidget = new StockQueryWidget(searchListModel, this);
-    innerLayoutPanel.addWest(queryWidget, 60.0);
-
-    DockLayoutPanel favoritesLayoutPanel = new DockLayoutPanel(Unit.EM);
-    favoritesLayoutPanel.addNorth(new Label("Portfolio / Favorites"), 2.0);
-    favoritesLayoutPanel.add(new ScrollPanel(favoritesTable));
-    innerLayoutPanel.add(favoritesLayoutPanel);
-    layoutPanel.add(innerLayoutPanel);
-
-    RootLayoutPanel.get().add(layoutPanel);
-
     update();
   }
 
+  public void transact(Transaction t) {
+    dataService.transact(t, new AsyncCallback<Transaction>() {
+      public void onFailure(Throwable caught) {
+        Window.alert("Error: " + caught.getMessage());
+      }
+
+      public void onSuccess(Transaction result) {
+        recordTransaction(result);
+        update();
+      }
+
+      /**
+       * Update transactions (list of all transactions),
+       * transactionTickers (set of all tickers involved in
+       * transactions), and transactionsByTicker (map from
+       * ticker to lists of transactions for that ticker).
+       */
+      private void recordTransaction(Transaction result) {
+        transactions.add(0, result);
+        String ticker = result.getTicker();
+        
+        // Update the next level of the transaction tree
+        // for the given ticker
+        ListListModel<Transaction> t =
+          transactionListListModelsByTicker.get(ticker);
+        if (t == null) {
+          t = new ListListModel<Transaction>();
+          transactionListListModelsByTicker.put(ticker, t);
+        }
+        t.getList().add(result);
+      }
+    });
+  }
+
   /**
    * Set or unset a ticker symbol as a 'favorite'.
    *
@@ -345,7 +289,7 @@
    *
    * @param response the stock response
    */
-  private void processStockResponse(StockResponse response) {
+  public void processStockResponse(StockResponse response) {
     // Update the search list.
     StockQuoteList searchResults = response.getSearchResults();
     searchListModel.updateDataSize(response.getNumSearchResults(), true);
@@ -367,7 +311,7 @@
     updateTimer.schedule(UPDATE_DELAY);
   }
 
-  private void updateFavorites(StockResponse response) {
+  public void updateFavorites(StockResponse response) {
     // Update the favorites list.
     StockQuoteList favorites = response.getFavorites();
     favoritesListModel.updateDataSize(response.getNumFavorites(), true);
@@ -375,7 +319,7 @@
         favorites.size(), favorites);
   }
 
-  private void updateSector(StockResponse response) {
+  public void updateSector(StockResponse response) {
     // Update the sector list.
     StockQuoteList sectorList = response.getSector();
     if (sectorList != null) {
@@ -385,4 +329,19 @@
           sectorList.size(), sectorList);
     }
   }
+
+  @UiFactory
+  FavoritesWidget createFavoritesWidget() {
+    return new FavoritesWidget(favoritesListModel);
+  }
+
+  @UiFactory
+  StockQueryWidget createQueryWidget() {
+    return new StockQueryWidget(searchListModel, this);
+  }
+
+  @UiFactory
+  SideBySideTreeView createTransactionTree() {
+    return new SideBySideTreeView(treeModel, null, 200, 200);
+  }
 }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.ui.xml b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.ui.xml
new file mode 100644
index 0000000..a8da167
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.ui.xml
@@ -0,0 +1,60 @@
+<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'
+  xmlns:s='urn:import:com.google.gwt.bikeshed.sample.stocks.client'>
+
+  <ui:style field='common' src='common.css'/>
+
+  <g:DockLayoutPanel unit='EM'>
+    <g:north size='4'>
+      <g:HTML styleName='{common.bg} {common.header-main}'>Day Trader</g:HTML>
+    </g:north>
+
+    <g:west size='16'>
+      <g:DockLayoutPanel unit='EM'>
+        <g:north size='12'>
+          <g:HTMLPanel styleName='{common.bg}'>
+            <div class='{common.header}'>Your Stats</div>
+            <table>
+              <tr><td>Available cash:</td><td><g:InlineLabel ui:field='cashLabel'/></td></tr>
+              <tr><td>Net worth:</td><td><g:InlineLabel ui:field='netWorthLabel'/></td></tr>
+            </table>
+          </g:HTMLPanel>
+        </g:north>
+
+        <g:center>
+          <g:ScrollPanel styleName='{common.bg}'>
+            <g:HTMLPanel>
+              <div class='{common.header}'>Everyone Else</div>
+              <table>
+                <tr><td>Dan Rice</td><td>$10000</td></tr>
+                <tr><td>Joel Webber</td><td>$10000</td></tr>
+                <tr><td>John Labanca</td><td>$10000</td></tr>
+              </table>
+            </g:HTMLPanel>
+          </g:ScrollPanel>
+        </g:center>
+      </g:DockLayoutPanel>
+    </g:west>
+
+    <g:north size="18">
+      <g:ScrollPanel styleName='{common.bg}'>
+        <t:SideBySideTreeView ui:field='transactionTree'/>
+      </g:ScrollPanel>
+    </g:north>
+
+    <g:center>
+      <g:DockLayoutPanel unit='PCT'>
+        <g:west size="50">
+          <s:StockQueryWidget styleName='{common.bg}' ui:field='queryWidget'/>
+        </g:west>
+
+        <g:center>
+          <s:FavoritesWidget styleName='{common.bg}' ui:field='favoritesWidget'/>
+        </g:center>
+      </g:DockLayoutPanel>       
+    </g:center>
+  </g:DockLayoutPanel>
+</ui:UiBinder>
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/common.css b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/common.css
new file mode 100644
index 0000000..8ab5593
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/common.css
@@ -0,0 +1,47 @@
+/* text-overflow: ellipsis; */
+
+.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;
+  -gecko-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: 100%;
+  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;
+}
diff --git a/bikeshed/war/Stocks.css b/bikeshed/war/Stocks.css
index 7a8f49d..f241a27 100644
--- a/bikeshed/war/Stocks.css
+++ b/bikeshed/war/Stocks.css
@@ -1,4 +1,16 @@
-/** Add css rules here for your application. */
+body {
+  background: url(bg.png) repeat-x;
+  background-color: rgb(216, 220, 224);
+  color: black;
+  margin: 8px;
+  margin-top: 3px;
+}
+
+body, table {
+  font-family: Helvetica Neue Light, Helvetica, Arial, sans-serif; */
+  font-weight: light;
+  font-size: small;
+}
 
 div.gwt-sstree-column {
   overflow-y: scroll;
@@ -7,7 +19,6 @@
 }
 
 div.gwt-sstree {
-  border: 2px solid black;
 }
 
 div.gwt-sstree-selectedItem {
@@ -53,3 +64,19 @@
 #closeButton {
   margin: 15px 6px 6px;
 }
+
+.gwt-DialogBox {
+  border: 8px solid white;
+  border-right: 11px solid white;
+  border-bottom: 11px solid white;
+  -webkit-border-image: url(blueborder.png) 8 11 11 8 round round;
+  -gecko-border-image: url(blueborder.png) 8 11 11 8 round round;
+}
+
+.gwt-DialogBox .Caption {
+  font-weight: light;
+  font-size: 12pt;
+  text-align: center;
+  margin-bottom: 0.5em;
+  border-bottom: 1px solid #ccc;
+}
diff --git a/bikeshed/war/bg.png b/bikeshed/war/bg.png
new file mode 100644
index 0000000..7617246
--- /dev/null
+++ b/bikeshed/war/bg.png
Binary files differ
diff --git a/bikeshed/war/blueborder.png b/bikeshed/war/blueborder.png
new file mode 100644
index 0000000..e4957f5
--- /dev/null
+++ b/bikeshed/war/blueborder.png
Binary files differ
diff --git a/bikeshed/war/border.png b/bikeshed/war/border.png
new file mode 100644
index 0000000..6338b88
--- /dev/null
+++ b/bikeshed/war/border.png
Binary files differ