Revision: 8092
Author: jlaba...@google.com
Date: Tue May 11 09:34:32 2010
Log: Fixes a bug where stale responses would update the ExpenseList. Also changes the notes section of the Expense Details to be text unless the edit button is clicked. Fixes the round trip validation associated with updating the approval/denial for expenses.

Review by: j...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=8092

Added:
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/list/client/simplePagerLoading.gif /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/cellTreeLoadingClean.gif /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/pendingNotes.gif
Modified:
/branches/2.1/bikeshed/src/com/google/gwt/app/client/CellListPlacePickerView.java /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/list/client/SimplePager.java /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTree.java /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTreeClean.css /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseDetails.java /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseDetails.ui.xml /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseList.java /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/Expenses.java
 /branches/2.1/user/src/com/google/gwt/view/client/ListViewAdapter.java

=======================================
--- /dev/null
+++ /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/list/client/simplePagerLoading.gif Tue May 11 09:34:32 2010
@@ -0,0 +1,25 @@
+GIF89a ò ÿÿÿ ÂÂÂBBB bbb‚‚‚’’’!ÿ NETSCAPE2.0 !þ Created with ajaxload.info !ù + , 3 ºÜþ0ÊIk c : œ N˜f E±1º ™Á¶.`ÄÂqÐ-[ 9ݦ 9 JkçH !ù + , 4 ºÜþNŒ! „ »°æŠDqBQT`1 `LE[ ¨| +µußía € × â†C ²%$* !ù + , 6 º2#+ÊAÈ Ì”V/ +c
+ ô NñIBa˜«p
+ð
+̳½
+ƨ+ Yí ü ƒÃ 2©d Ÿ¿ !ù + , 3 ºb%+Ê2†‘ìœV_
+‹¦
+!  1D‡a
+ ªF‚°Ñ bR]ó= 08, Ȥr9L !ù + , 2 ºr'+Jçd ð óL &vÃ`\bT”
+„¹
+hYB)ÏÊ@ +é< Ã&, ȤR’ !ù + , 3 º  9 ãtç¼Úž0 Ç +à!.B¶ ÊW¬¢1 sa»°5÷• 0° ‰»Ÿm)J !ù + , 2 ºÜþð ÙœU]š îÚqp•`ˆÝaœÝ4– +AFÅ0 `›¶ + Â@ ›1€ÂÖΑ !ù + , 2 ºÜþ0ÊI«eBÔœ)× + à ŽÇq 10©Ê°®P Âa VÚ¥ ub ‚ž[ ; =======================================
--- /dev/null
+++ /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/cellTreeLoadingClean.gif Tue May 11 09:34:32 2010
@@ -0,0 +1,25 @@
+GIF89a ò ÿÿÿnyŠÛÞâ“›¨nyŠ¥¬¶·½ÅÀÅÌ!ÿ NETSCAPE2.0 !þ Created with ajaxload.info !ù + , 3 ºÜþ0ÊIk c : œ N˜f E±1º ™Á¶.`ÄÂqÐ-[ 9ݦ 9 JkçH !ù + , 4 ºÜþNŒ! „ »°æŠDqBQT`1 `LE[ ¨| +µußía € × â†C ²%$* !ù + , 6 º2#+ÊAÈ Ì”V/ +c
+ ô NñIBa˜«p
+ð
+̳½
+ƨ+ Yí ü ƒÃ 2©d Ÿ¿ !ù + , 3 ºb%+Ê2†‘ìœV_
+‹¦
+!  1D‡a
+ ªF‚°Ñ bR]ó= 08, Ȥr9L !ù + , 2 ºr'+Jçd ð óL &vÃ`\bT”
+„¹
+hYB)ÏÊ@ +é< Ã&, ȤR’ !ù + , 3 º  9 ãtç¼Úž0 Ç +à!.B¶ ÊW¬¢1 sa»°5÷• 0° ‰»Ÿm)J !ù + , 2 ºÜþð ÙœU]š îÚqp•`ˆÝaœÝ4– +AFÅ0 `›¶ + Â@ ›1€ÂÖΑ !ù + , 2 ºÜþ0ÊI«eBÔœ)× + à ŽÇq 10©Ê°®P Âa VÚ¥ ub ‚ž[ ; =======================================
--- /dev/null
+++ /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/pendingNotes.gif Tue May 11 09:34:32 2010
@@ -0,0 +1,32 @@
+GIF89a ó ÿÿÿKJJKJJ¦¦¦›ššÁÁÁÏÏÏÜÛÛççç³²²îî“ !þ Created with ajaxload.info !ù + !ÿ NETSCAPE2.0 , + ÈI«½8OÁ»ÿÜ@ Æ `áXžWJš¨ ¾¬å®ñŒ·² +ó  GC, ” !ù + , + ÈI«½8OÁ»ÿ\‘ Ä `áXžWJš¨ ¾¬å®ñŒ·² +ó  GC, ” !ù + , + ÈI«½8OÁ»ÿÜa ...@`áxžwjš¨ ¾¬å®ñŒ·² +ó  GC, ” !ù + , 1 ÈI«½8OÁ»ÿœ‚ +F‘ „ Žå™V+i¢ª Ên}·4l³³ %Æ n...@ÈŽfÉl:) !ù + , 6 ÈI«½8OÁ»ÿœ¤ ‡Q$ A +ÀXžé*ˆ¤‰ªÛÜÖ0.±.[,G{ÝdE¡ jz4ШtJ‰ !ù + , 6 ÈI«½8OÁ»ÿ
+¥ ‡Q$ !
+ÓXžé*ˆ¤‰ª +¹vœÏ­ § ð†2Úë& 9‹š¨tJ !ù + , 1 ÈI«½8OÁ»ÿœ¥ ‡Q$ Vcy¦+Õš¨*ˆ$ +ßlþÚ8w-6...@h fÉl:) !ù + , + ÈI«½8OÁ»ÿ +¦ ‡± á5–gj­&*ˆdìVp;«µN³2 ð¦) È !ù + , & ÈI«½8OÁ»ÿœ¶ C fcyb©)ˆ¤ «/ ¯W îžæÿÀ % !ù + , + ÈI«½8OÁ»ÿ +¶ CR á5–gj­&*ˆdìVp;«µN³2 ð¦) È !ù + + , 1 ÈI«½8OÁ»ÿœµ CR Vcy¦+Õš¨*ˆ$ +ßlþÚ8w-6...@h fÉl:) !ù + , 6 ÈI«½8OÁ»ÿ
+µ CR  "
+ÓXžé*ˆ¤‰ª +¹vœÏ­ § ð†2Úë& 9‹š¨tJ !ù + , 6 ÈI«½8OÁ»ÿœ´ CR B +ÀXžé*ˆ¤‰ªÛÜÖ0.±.[,G{ÝdE¡ jz4ШtJ‰ !ù + + , 1 ÈI«½8OÁ»ÿÜB Ia +ˆ Žå™V+i¢ª Ên}·4l³³ %Æ n...@ÈŽfÉl:) ; ======================================= --- /branches/2.1/bikeshed/src/com/google/gwt/app/client/CellListPlacePickerView.java Tue May 11 09:04:15 2010 +++ /branches/2.1/bikeshed/src/com/google/gwt/app/client/CellListPlacePickerView.java Tue May 11 09:34:32 2010
@@ -53,7 +53,6 @@
     initWidget(cellList);
     cellList.setSelectionModel(smodel);
     smodel.addSelectionChangeHandler(new SelectionChangeHandler() {
-      @Override
       public void onSelectionChange(SelectionChangeEvent event) {
         if (listener != null) {
           listener.placePicked(smodel.getSelectedObject());
@@ -80,7 +79,6 @@
     cellList.setPageSize(size);
   }

-  @Override
   public void setValues(List<P> places, Renderer<P> renderer) {
     // Replace the current renderer.
     this.renderer = renderer;
=======================================
--- /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/list/client/SimplePager.java Thu May 6 19:50:57 2010 +++ /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/list/client/SimplePager.java Tue May 11 09:34:32 2010
@@ -22,10 +22,11 @@
 import com.google.gwt.resources.client.CssResource;
 import com.google.gwt.resources.client.ImageResource;
 import com.google.gwt.uibinder.client.UiConstructor;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.HasVerticalAlignment;
 import com.google.gwt.user.client.ui.HorizontalPanel;
 import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.view.client.PagingListView;

 /**
@@ -68,6 +69,11 @@
      */
     ImageResource simplePagerLastPageDisabled();

+    /**
+     * The icon to use while the page is loading.
+     */
+    ImageResource simplePagerLoading();
+
     /**
      * The image used to go to the next page.
      */
@@ -126,9 +132,19 @@
   }

   private final Image firstPage;
-  private final Label label = new Label();
+
+  /**
+   * We use an {...@link HTML} so we can embed the loading image.
+   */
+  private final HTML label = new HTML();
+
   private final Image lastPage;

+  /**
+   * The html used to render the loading image.
+   */
+  private final String loadingImageHtml;
+
   /**
    * Set to true when the next and last buttons are disabled.
    */
@@ -187,6 +203,10 @@
     this.style = resources.simplePagerStyle();
     this.style.ensureInjected();

+    // Create the loading image.
+ AbstractImagePrototype loadingProto = AbstractImagePrototype.create(resources.simplePagerLoading());
+    loadingImageHtml = loadingProto.getHTML();
+
     // Create the buttons.
     firstPage = new Image(resources.simplePagerFirstPage());
     lastPage = new Image(resources.simplePagerLastPage());
@@ -288,6 +308,18 @@
       }
     }
   }
+
+  /**
+ * Let the page know that the table is loading. Call this method to clear all
+   * data from the table and hide the current range when new data is being
+   * loaded into the table.
+   */
+  public void startLoading() {
+    PagingListView<T> listView = getPagingListView();
+    listView.setDataSize(0, true);
+    onRangeOrSizeChanged(listView);
+    label.setHTML(loadingImageHtml);
+  }

   /**
* Get the text to display in the pager that reflects the state of the pager.
=======================================
--- /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTree.java Mon May 10 15:03:36 2010 +++ /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTree.java Tue May 11 09:34:32 2010
@@ -358,6 +358,9 @@
     @Source("cellTreeClosedArrow.png")
     ImageResource cellTreeClosedItem();

+    @Source("cellTreeLoadingClean.gif")
+    ImageResource cellTreeLoading();
+
     @Source("cellTreeOpenArrow.png")
     ImageResource cellTreeOpenItem();

=======================================
--- /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTreeClean.css Mon May 10 06:16:12 2010 +++ /branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTreeClean.css Tue May 11 09:34:32 2010
@@ -40,6 +40,7 @@

 .topItemImageValue {
   border-bottom: 1px solid #6f7277;
+  padding-bottom: 1px;
 }

 @sprite .selectedItem {
=======================================
--- /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseDetails.java Mon May 10 15:03:36 2010 +++ /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseDetails.java Tue May 11 09:34:32 2010
@@ -29,8 +29,13 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.dom.client.SelectElement;
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
 import com.google.gwt.event.logical.shared.CloseEvent;
 import com.google.gwt.event.logical.shared.CloseHandler;
 import com.google.gwt.i18n.client.DateTimeFormat;
@@ -43,6 +48,7 @@
 import com.google.gwt.sample.expenses.gwt.request.ExpenseRecordChanged;
 import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
 import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
+import com.google.gwt.sample.expenses.gwt.request.ReportRecordChanged;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiFactory;
 import com.google.gwt.uibinder.client.UiField;
@@ -77,7 +83,7 @@
  * including the list of expenses.
  */
 public class ExpenseDetails extends Composite implements
-    Receiver<List<ExpenseRecord>>, ExpenseRecordChanged.Handler {
+    ExpenseRecordChanged.Handler, ReportRecordChanged.Handler {

   /**
    * String indicating approval.
@@ -335,9 +341,21 @@

   ExpensesRequestFactory expensesRequestFactory;

+  @UiField
+  Element notes;
+
   @UiField
   TextBox notesBox;

+  @UiField
+  Anchor notesEditLink;
+
+  @UiField
+  Element notesEditLinkWrapper;
+
+  @UiField
+  Element notesPending;
+
   @UiField
   Element reportName;

@@ -372,6 +390,11 @@

   private Comparator<ExpenseRecord> lastComparator;

+  /**
+   * Keep track of the last receiver so we can ignore stale responses.
+   */
+  private Receiver<List<ExpenseRecord>> lastReceiver;
+
   /**
    * The current report being displayed.
    */
@@ -389,6 +412,38 @@
     items.setKeyProvider(Expenses.EXPENSE_RECORD_KEY_PROVIDER);
     table.setKeyProvider(items);
     items.addView(table);
+
+    // Switch to edit notes.
+    notesEditLink.addClickHandler(new ClickHandler() {
+      public void onClick(ClickEvent event) {
+        setNotesEditState(true, false, report.getNotes());
+      }
+    });
+
+    // Switch to view mode.
+    notesBox.addBlurHandler(new BlurHandler() {
+      public void onBlur(BlurEvent event) {
+ // The text box will be blurred on cancel, so only save the notes if
+        // it is visible.
+        if (notesBox.isVisible()) {
+          saveNotes();
+        }
+      }
+    });
+    notesBox.addKeyUpHandler(new KeyUpHandler() {
+      public void onKeyUp(KeyUpEvent event) {
+        int keyCode = event.getNativeKeyCode();
+        switch (keyCode) {
+          case KeyCodes.KEY_ENTER:
+            saveNotes();
+            break;
+          case KeyCodes.KEY_ESCAPE:
+            // Cancel the edit.
+            setNotesEditState(false, false, report.getNotes());
+            break;
+        }
+      }
+    });
   }

   public Anchor getReportsLink() {
@@ -397,13 +452,20 @@

   public void onExpenseRecordChanged(ExpenseRecordChanged event) {
     ExpenseRecord newRecord = event.getRecord();
-    String id = newRecord.getId();
+    Object newKey = items.getKey(newRecord);

     int index = 0;
     List<ExpenseRecord> list = items.getList();
     for (ExpenseRecord r : list) {
-      if (r.getId().equals(id)) {
+      if (items.getKey(r).equals(newKey)) {
         list.set(index, newRecord);
+
+        // Update the view data if the approval has been updated.
+ ApprovalViewData avd = (ApprovalViewData) approvalColumn.getViewData(newKey);
+        if (avd != null
+            && avd.getPendingApproval().equals(newRecord.getApproval())) {
+          syncCommit(newRecord, null);
+        }
       }
       index++;
     }
@@ -414,11 +476,12 @@
     }
   }

-  public void onSuccess(List<ExpenseRecord> newValues) {
-    List<ExpenseRecord> list = new ArrayList<ExpenseRecord>(newValues);
-    sortExpenses(list, lastComparator);
-    items.setList(list);
-    refreshCost();
+  public void onReportChanged(ReportRecordChanged event) {
+    ReportRecord changed = event.getRecord();
+    if (report != null && report.getId().equals(changed.getId())) {
+      report = changed;
+      setNotesEditState(false, false, changed.getNotes());
+    }
   }

   public void setExpensesRequestFactory(
@@ -437,10 +500,11 @@
       EmployeeRecord employee) {
     this.report = report;
     reportName.setInnerText(report.getPurpose());
-    notesBox.setText(report.getNotes());
     costLabel.setInnerText("");
     approvedLabel.setInnerText("");
     unreconciledLabel.setInnerText("");
+    setNotesEditState(false, false, report.getNotes());
+    items.getList().clear();
     totalApproved = 0;

     // Update the breadcrumb.
@@ -683,8 +747,63 @@
    * Request the expenses.
    */
   private void requestExpenses() {
+    lastReceiver = new Receiver<List<ExpenseRecord>>() {
+      public void onSuccess(List<ExpenseRecord> newValues) {
+        if (this == lastReceiver) {
+ List<ExpenseRecord> list = new ArrayList<ExpenseRecord>(newValues);
+          sortExpenses(list, lastComparator);
+          items.setList(list);
+          refreshCost();
+        }
+      }
+    };
     expensesRequestFactory.expenseRequest().findExpensesByReport(
- report.getRef(Record.id)).forProperties(getExpenseColumns()).to(this).fire();
+        report.getRef(Record.id)).forProperties(getExpenseColumns()).to(
+        lastReceiver).fire();
+  }
+
+  /**
+   * Save the notes that the user entered in the notes box.
+   */
+  private void saveNotes() {
+    // Early exit if the notes haven't changed.
+    final String pendingNotes = notesBox.getText();
+    if (pendingNotes.equals(report.getNotes())) {
+      setNotesEditState(false, false, pendingNotes);
+      return;
+    }
+
+    // Switch to the pending view.
+    setNotesEditState(false, true, pendingNotes);
+
+    // Submit the delta.
+ DeltaValueStore deltas = expensesRequestFactory.getValueStore().spawnDeltaView();
+    deltas.set(ReportRecord.notes, report, pendingNotes);
+    expensesRequestFactory.syncRequest(deltas).to(
+        new Receiver<Set<SyncResult>>() {
+          public void onSuccess(Set<SyncResult> response) {
+            // We expect onReportChanged to be called.
+          }
+        }).fire();
+  }
+
+  /**
+   * Set the state of the notes section.
+   *
+   * @param editable true for edit state, false for view state
+   * @param pending true if changes are pending, false if not
+   * @param notesText the current notes
+   */
+  private void setNotesEditState(boolean editable, boolean pending,
+      String notesText) {
+    notesBox.setText(notesText);
+    notes.setInnerText(notesText);
+
+    notesBox.setVisible(editable && !pending);
+    setVisible(notes, !editable);
+    setVisible(notesEditLinkWrapper, !editable && !pending);
+    setVisible(notesPending, pending);
+    notesBox.setFocus(editable);
   }

   private void sortExpenses(List<ExpenseRecord> list,
@@ -706,12 +825,12 @@
       if (avd != null) {
         avd.reject(message);
       }
-
-      // Redraw the table so the changes are applied.
-      table.redraw();
     } else {
       approvalColumn.setViewData(key, null);
     }
+
+    // Redraw the table so the changes are applied.
+    table.redraw();
   }

private void updateExpenseRecord(final ExpenseRecord record, String approval,
@@ -748,9 +867,6 @@
               syncCommit(record, errorMessage.length() > 0 ? errorMessage
                   : null);
             }
-
-            // Request the updated expenses.
-            requestExpenses();
           }
         }).fire();
   }
=======================================
--- /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseDetails.ui.xml Tue May 11 03:34:50 2010 +++ /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseDetails.ui.xml Tue May 11 09:34:32 2010
@@ -1,14 +1,25 @@
 <!DOCTYPE ui:UiBinder SYSTEM 'http://dl.google.com/gwt/DTD/xhtml.ent'>
-<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
+<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'>

-  <ui:style field='desktop' src='desktop.css' />
-
-  <ui:image field='cornerTopRight' />
-  <ui:image field='cornerTopLeft' />
-  <ui:image field='cornerBottomRight' />
-  <ui:image field='cornerBottomLeft' />
-  <ui:image field='leftArrow' />
+  <ui:style
+    field='desktop'
+    src='desktop.css' />
+
+  <ui:image
+    field='cornerTopRight' />
+  <ui:image
+    field='cornerTopLeft' />
+  <ui:image
+    field='cornerBottomRight' />
+  <ui:image
+    field='cornerBottomLeft' />
+  <ui:image
+    field='leftArrow' />
+  <ui:image
+    field='pendingNotes' />

   <ui:style>
     .details {
@@ -20,20 +31,23 @@
       gwt-image: 'leftArrow';
     }

-    .reportLink {
-      margin-left: 5px;
+    .link {
       text-decoration: underline;
       color: black;
       cursor: hand;
       cursor: pointer;
     }

-    .reportLink:hover {
+    .link:hover {
       text-decoration: underline;
       color: black;
       cursor: hand;
       cursor: pointer;
     }
+
+    .reportLink {
+      margin-left: 5px;
+    }

     .label {
       width: 250px;
@@ -51,69 +65,109 @@

     .notesColumn {
       width: 400px;
-      padding-right: 100px;
+      padding-right: 100px;
     }

-    .notes {
-      width: 400px;
+    .notesTextBox {
+      width: 350px;
       border: 1px solid #d7dde8;
       padding: 3px;
     }
+
+    .notesEditLink {
+      font-weight: bold;
+    }
+
+    @sprite .pendingNotes {
+      gwt-image: 'pendingNotes';
+      margin-left: 10px;
+    }
   </ui:style>

-  <g:DockLayoutPanel unit='PX'>
-    <g:north size='180'>
-      <g:HTMLPanel styleName='{desktop.breadcrumbBar}'>
-        <table align='center' width='100%' cellspacing='0' cellpadding='0'>
+  <g:DockLayoutPanel
+    unit='PX'>
+    <g:north
+      size='180'>
+      <g:HTMLPanel
+        styleName='{desktop.breadcrumbBar}'>
+        <table
+          align='center'
+          width='100%'
+          cellspacing='0'
+          cellpadding='0'>
           <!-- Top of 9 box. -->
           <tr>
-            <td class='{desktop.breadcrumbCorner}'>
-              <div class='{desktop.breadcrumbCornerTopLeft}' />
+            <td
+              class='{desktop.breadcrumbCorner}'>
+              <div
+                class='{desktop.breadcrumbCornerTopLeft}' />
             </td>
-            <td class='{desktop.breadcrumbBorder}'>
-              <div class='{desktop.breadcrumbBorderInner}' />
+            <td
+              class='{desktop.breadcrumbBorder}'>
+              <div
+                class='{desktop.breadcrumbBorderInner}' />
             </td>
-            <td class='{desktop.breadcrumbCorner}'>
-              <div class='{desktop.breadcrumbCornerTopRight}' />
+            <td
+              class='{desktop.breadcrumbCorner}'>
+              <div
+                class='{desktop.breadcrumbCornerTopRight}' />
             </td>
           </tr>
           <tr>
             <!-- Left of 9 box. -->
-            <td class='{desktop.breadcrumbBorder}'>
-              <div class='{desktop.breadcrumbBorderInner}' />
+            <td
+              class='{desktop.breadcrumbBorder}'>
+              <div
+                class='{desktop.breadcrumbBorderInner}' />
             </td>
             <!-- Breadcrumb. -->
-            <td class='{desktop.breadcrumb} {desktop.breadcrumbBorder}'
+            <td
+              class='{desktop.breadcrumb} {desktop.breadcrumbBorder}'
               ui:field='reportName'>
             </td>
             <!-- Right of 9 box. -->
-            <td class='{desktop.breadcrumbBorder}'>
-              <div class='{desktop.breadcrumbBorderInner}' />
+            <td
+              class='{desktop.breadcrumbBorder}'>
+              <div
+                class='{desktop.breadcrumbBorderInner}' />
             </td>
           </tr>
           <!-- Bottom of 9 box. -->
           <tr>
-            <td class='{desktop.breadcrumbCorner}'>
-              <div class='{desktop.breadcrumbCornerBottomLeft}' />
+            <td
+              class='{desktop.breadcrumbCorner}'>
+              <div
+                class='{desktop.breadcrumbCornerBottomLeft}' />
             </td>
-            <td class='{desktop.breadcrumbBorder}'>
-              <div class='{desktop.breadcrumbBorderInner}' />
+            <td
+              class='{desktop.breadcrumbBorder}'>
+              <div
+                class='{desktop.breadcrumbBorderInner}' />
             </td>
-            <td class='{desktop.breadcrumbCorner}'>
-              <div class='{desktop.breadcrumbCornerBottomRight}' />
+            <td
+              class='{desktop.breadcrumbCorner}'>
+              <div
+                class='{desktop.breadcrumbCornerBottomRight}' />
             </td>
           </tr>

           <!-- Link back to report list. -->
           <tr>
-            <td colspan='3' style='padding-top:6px;'>
-              <table cellpadding='0' cellspacing='0'>
+            <td
+              colspan='3'
+              style='padding-top:6px;'>
+              <table
+                cellpadding='0'
+                cellspacing='0'>
                 <tr>
                   <td>
-                    <div class='{style.leftArrow}' />
+                    <div
+                      class='{style.leftArrow}' />
                   </td>
                   <td>
- <g:Anchor styleName='{style.reportLink}' ui:field='reportsLink' />
+                    <g:Anchor
+                      styleName='{style.reportLink} {style.link}'
+                      ui:field='reportsLink' />
                   </td>
                 </tr>
               </table>
@@ -122,36 +176,78 @@
         </table>

         <!-- Details about the Report. -->
-        <table class='{style.details}' cellpadding='0' cellspacing='0'>
+        <table
+          class='{style.details}'
+          cellpadding='0'
+          cellspacing='0'>
           <tr>
-            <td class='{style.label}'>
+            <td
+              class='{style.label}'>
               Cost:
             </td>
-            <td align='right' class='{style.amount}' ui:field='costLabel'>
+            <td
+              align='right'
+              class='{style.amount}'
+              ui:field='costLabel'>
             </td>
-            <td rowspan='3'>
+            <td
+              rowspan='3'>
               &nbsp;
             </td>
-            <td class='{style.label} {style.notesColumn}'>
-              Notes:
+            <td
+              class='{style.notesColumn}'>
+              <table
+                cellspacing='0'
+                cellpadding='0'>
+                <tr>
+                  <td>
+                    Notes:
+                  </td>
+                  <td>
+                    <div
+                      class='{style.pendingNotes}'
+                      ui:field='notesPending' />
+                  </td>
+                </tr>
+              </table>
             </td>
           </tr>
           <tr>
-            <td class='{style.label} {style.dotted}'>
+            <td
+              class='{style.label} {style.dotted}'>
               Approved:
             </td>
-            <td align='right' class='{style.amount}  {style.dotted}'
+            <td
+              align='right'
+              class='{style.amount}  {style.dotted}'
               ui:field='approvedLabel'>
             </td>
-            <td rowspan='2' class='{style.notesColumn}' valign='top'>
-              <g:TextBox styleName='{style.notes}' ui:field='notesBox' />
+            <td
+              rowspan='2'
+              class='{style.notesColumn}'
+              valign='top'>
+              <g:TextBox
+                styleName='{style.notesTextBox}'
+                ui:field='notesBox' />
+              <span
+                ui:field='notes' />
+              <span
+                ui:field='notesEditLinkWrapper'>
+                (<g:Anchor
+                  styleName='{style.link} {style.notesEditLink}'
+                  ui:field='notesEditLink'>edit</g:Anchor>)
+              </span>
             </td>
           </tr>
           <tr>
-            <td class='{style.label}'>
+            <td
+              class='{style.label}'>
               <b>Un-reconciled:</b>
             </td>
- <td align='right' class='{style.amount}' style='font-weight:bold'
+            <td
+              align='right'
+              class='{style.amount}'
+              style='font-weight:bold'
               ui:field='unreconciledLabel'>
             </td>
           </tr>
@@ -161,7 +257,9 @@

     <g:center>
       <g:ScrollPanel>
-        <l:CellTable addStyleNames='{desktop.table}' width='100%'
+        <l:CellTable
+          addStyleNames='{desktop.table}'
+          width='100%'
           ui:field='table' />
       </g:ScrollPanel>
     </g:center>
=======================================
--- /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseList.java Mon May 10 15:03:36 2010 +++ /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseList.java Tue May 11 09:34:32 2010
@@ -66,7 +66,7 @@
  * The list of expense reports on the left side of the app.
  */
 public class ExpenseList extends Composite implements
-    Receiver<List<ReportRecord>>, ReportRecordChanged.Handler {
+    ReportRecordChanged.Handler {

private static ExpenseListUiBinder uiBinder = GWT.create(ExpenseListUiBinder.class);

@@ -232,6 +232,16 @@
    */
   private String orderBy = ReportRecord.purpose.getName();

+  /**
+ * Keep track of the last receiver so that we know if a response is stale.
+   */
+  private Receiver<List<ReportRecord>> lastDataReceiver;
+
+  /**
+ * Keep track of the last receiver so that we know if a response is stale.
+   */
+  private Receiver<Long> lastDataSizeReceiver;
+
   private Listener listener;

   /**
@@ -310,10 +320,6 @@
       i++;
     }
   }
-
-  public void onSuccess(List<ReportRecord> newValues) {
- reports.updateViewData(table.getPageStart(), newValues.size(), newValues);
-  }

   /**
    * Set the current department and employee to filter on.
@@ -492,17 +498,30 @@
     // Request the total data size.
     if (isCountStale) {
       isCountStale = false;
-      requestFactory.reportRequest().countReportsBySearch(employeeId,
-          startsWith).to(new Receiver<Long>() {
+      pager.startLoading();
+      lastDataSizeReceiver = new Receiver<Long>() {
         public void onSuccess(Long response) {
-          reports.updateDataSize(response.intValue(), true);
-        }
-      }).fire();
+          if (this == lastDataSizeReceiver) {
+            reports.updateDataSize(response.intValue(), true);
+          }
+        }
+      };
+      requestFactory.reportRequest().countReportsBySearch(employeeId,
+          startsWith).to(lastDataSizeReceiver).fire();
     }

     // Request reports in the current range.
+    lastDataReceiver = new Receiver<List<ReportRecord>>() {
+      public void onSuccess(List<ReportRecord> newValues) {
+        if (this == lastDataReceiver) {
+          reports.updateViewData(table.getPageStart(), newValues.size(),
+              newValues);
+        }
+      }
+    };
+    // TODO(jlabanca): Pass the department into the query.
     requestFactory.reportRequest().findReportEntriesBySearch(employeeId,
startsWith, orderBy, range.getStart(), range.getLength()).forProperties(
-        reportColumns).to(this).fire();
+        reportColumns).to(lastDataReceiver).fire();
   }
 }
=======================================
--- /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/Expenses.java Thu May 6 12:36:08 2010 +++ /branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/Expenses.java Tue May 11 09:34:32 2010
@@ -91,6 +91,8 @@
     expenseList.setRequestFactory(requestFactory);
     eventBus.addHandler(ReportRecordChanged.TYPE, expenseList);

+    // Forward change events to the expense details.
     eventBus.addHandler(ExpenseRecordChanged.TYPE, expenseDetails);
+    eventBus.addHandler(ReportRecordChanged.TYPE, expenseDetails);
   }
 }
=======================================
--- /branches/2.1/user/src/com/google/gwt/view/client/ListViewAdapter.java Wed May 5 13:18:30 2010 +++ /branches/2.1/user/src/com/google/gwt/view/client/ListViewAdapter.java Tue May 11 09:34:32 2010
@@ -400,8 +400,7 @@
    */
   public void setList(List<T> wrappee) {
     listWrapper = new ListWrapper(wrappee);
-    updateDataSize(listWrapper.size(), true);
-    updateViewData(0, listWrapper.size(), listWrapper);
+    listWrapper.flush();
   }

   @Override

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to