Brings history support to samples/expenses. Doesn't handle paging --
sorry Chris, out of time -- and doesn't separate widgets from their
presenters. But still not a bad clean up, and hey! Book marks!
Review at http://gwt-code-reviews.appspot.com/1020801
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9108 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/DenialPopup.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/DenialPopup.java
new file mode 100644
index 0000000..0ec6adf
--- /dev/null
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/DenialPopup.java
@@ -0,0 +1,94 @@
+/*
+ * 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.expenses.client;
+
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.sample.expenses.client.style.Styles;
+import com.google.gwt.sample.expenses.shared.ExpenseProxy;
+import com.google.gwt.user.client.ui.Button;
+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.PopupPanel;
+import com.google.gwt.user.client.ui.TextBox;
+
+/**
+ * The popup used to enter the rejection reason.
+ */
+ class DenialPopup extends PopupPanel {
+ private final Button cancelButton = new Button("Cancel",
+ new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ reasonDenied = "";
+ hide();
+ }
+ });
+ private final Button confirmButton = new Button("Confirm",
+ new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ reasonDenied = reasonBox.getText();
+ hide();
+ }
+ });
+
+ private ExpenseProxy expenseRecord;
+ private final TextBox reasonBox = new TextBox();
+ private String reasonDenied;
+
+ public DenialPopup() {
+ super(false, true);
+ setStyleName(Styles.common().popupPanel());
+ setGlassEnabled(true);
+ confirmButton.setWidth("11ex");
+ cancelButton.setWidth("11ex");
+ reasonBox.getElement().getStyle().setMarginLeft(10.0, Unit.PX);
+ reasonBox.getElement().getStyle().setMarginRight(10.0, Unit.PX);
+
+ HorizontalPanel hPanel = new HorizontalPanel();
+ hPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
+ hPanel.add(new HTML("<b>Reason:</b>"));
+ hPanel.add(reasonBox);
+ hPanel.add(confirmButton);
+ hPanel.add(cancelButton);
+ setWidget(hPanel);
+ cancelButton.getElement().getParentElement().getStyle().setPaddingLeft(
+ 5.0, Unit.PX);
+ }
+
+ public ExpenseProxy getExpenseRecord() {
+ return expenseRecord;
+ }
+
+ public String getReasonDenied() {
+ return reasonDenied;
+ }
+
+ public void popup() {
+ center();
+ reasonBox.setFocus(true);
+ }
+
+ public void setExpenseRecord(ExpenseProxy expenseRecord) {
+ this.expenseRecord = expenseRecord;
+ }
+
+ public void setReasonDenied(String reasonDenied) {
+ this.reasonDenied = reasonDenied;
+ reasonBox.setText(reasonDenied);
+ }
+}
\ No newline at end of file
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseDetails.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java
similarity index 89%
rename from samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseDetails.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java
index eea8b71..455e0cf 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseDetails.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.sample.expenses.client;
+import com.google.gwt.activity.shared.Activity;
import com.google.gwt.cell.client.AbstractInputCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.DateCell;
@@ -27,7 +28,6 @@
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.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -50,6 +50,8 @@
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+import com.google.gwt.sample.expenses.client.place.ReportListPlace;
+import com.google.gwt.sample.expenses.client.place.ReportPlace;
import com.google.gwt.sample.expenses.client.style.Styles;
import com.google.gwt.sample.expenses.shared.EmployeeProxy;
import com.google.gwt.sample.expenses.shared.ExpenseProxy;
@@ -63,13 +65,11 @@
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
-import com.google.gwt.user.client.ui.HasVerticalAlignment;
-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.TextBox;
@@ -89,9 +89,43 @@
* Details about the current expense report on the right side of the app,
* including the list of expenses.
*/
-public class ExpenseDetails extends Composite {
+public class ExpenseReportDetails extends Composite implements Activity {
- interface ExpenseDetailsUiBinder extends UiBinder<Widget, ExpenseDetails> {
+ interface Binder extends UiBinder<Widget, ExpenseReportDetails> {
+ }
+
+ /**
+ * Fetches an employee and a report in parallel. A fine example of the kind of
+ * thing that will no longer be necessary when RequestFactory provides server
+ * side method chaining.
+ */
+ class EmployeeReportFetcher {
+ ReportProxy fetchedReport;
+ EmployeeProxy fetchedEmployee;
+
+ void Run(EntityProxyId<EmployeeProxy> employeeId,
+ EntityProxyId<ReportProxy> reportId,
+ final Receiver<EmployeeReportFetcher> callback) {
+ expensesRequestFactory.find(employeeId).fire(
+ new Receiver<EmployeeProxy>() {
+ @Override
+ public void onSuccess(EmployeeProxy response) {
+ fetchedEmployee = response;
+ if (fetchedReport != null) {
+ callback.onSuccess(EmployeeReportFetcher.this);
+ }
+ }
+ });
+ expensesRequestFactory.find(reportId).fire(new Receiver<ReportProxy>() {
+ @Override
+ public void onSuccess(ReportProxy response) {
+ fetchedReport = response;
+ if (fetchedEmployee != null) {
+ callback.onSuccess(EmployeeReportFetcher.this);
+ }
+ }
+ });
+ }
}
/**
@@ -287,72 +321,6 @@
}
}
- /**
- * The popup used to enter the rejection reason.
- */
- private class DenialPopup extends PopupPanel {
- private final Button cancelButton = new Button("Cancel",
- new ClickHandler() {
- public void onClick(ClickEvent event) {
- reasonDenied = "";
- hide();
- }
- });
- private final Button confirmButton = new Button("Confirm",
- new ClickHandler() {
- public void onClick(ClickEvent event) {
- reasonDenied = reasonBox.getText();
- hide();
- }
- });
-
- private ExpenseProxy expenseRecord;
- private final TextBox reasonBox = new TextBox();
- private String reasonDenied;
-
- public DenialPopup() {
- super(false, true);
- setStyleName(Styles.common().popupPanel());
- setGlassEnabled(true);
- confirmButton.setWidth("11ex");
- cancelButton.setWidth("11ex");
- reasonBox.getElement().getStyle().setMarginLeft(10.0, Unit.PX);
- reasonBox.getElement().getStyle().setMarginRight(10.0, Unit.PX);
-
- HorizontalPanel hPanel = new HorizontalPanel();
- hPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
- hPanel.add(new HTML("<b>Reason:</b>"));
- hPanel.add(reasonBox);
- hPanel.add(confirmButton);
- hPanel.add(cancelButton);
- setWidget(hPanel);
- cancelButton.getElement().getParentElement().getStyle().setPaddingLeft(
- 5.0, Unit.PX);
- }
-
- public ExpenseProxy getExpenseRecord() {
- return expenseRecord;
- }
-
- public String getReasonDenied() {
- return reasonDenied;
- }
-
- public void popup() {
- center();
- reasonBox.setFocus(true);
- }
-
- public void setExpenseRecord(ExpenseProxy expenseRecord) {
- this.expenseRecord = expenseRecord;
- }
-
- public void setReasonDenied(String reasonDenied) {
- this.reasonDenied = reasonDenied;
- reasonBox.setText(reasonDenied);
- }
- }
-
private static Template template;
/**
@@ -365,34 +333,25 @@
*/
private static final int REFRESH_INTERVAL = 5000;
- private static ExpenseDetailsUiBinder uiBinder = GWT.create(ExpenseDetailsUiBinder.class);
+ private static Binder uiBinder = GWT.create(Binder.class);
- @UiField
- Element approvedLabel;
+ @UiField Element approvedLabel;
- @UiField
- Element costLabel;
+ @UiField Element costLabel;
- @UiField
- Element notes;
+ @UiField Element notes;
- @UiField
- TextBox notesBox;
+ @UiField TextBox notesBox;
- @UiField
- Anchor notesEditLink;
+ @UiField Anchor notesEditLink;
- @UiField
- Element notesEditLinkWrapper;
+ @UiField Element notesEditLinkWrapper;
- @UiField
- Element notesPending;
+ @UiField Element notesPending;
- @UiField
- Element reportName;
+ @UiField Element reportName;
- @UiField
- Anchor reportsLink;
+ @UiField Anchor reportsLink;
@UiField(provided = true)
CellTable<ExpenseProxy> table;
@@ -464,7 +423,9 @@
*/
private double totalApproved;
- public ExpenseDetails(ExpensesRequestFactory expensesRequestFactory) {
+ private ReportPlace place;
+
+ public ExpenseReportDetails(ExpensesRequestFactory expensesRequestFactory) {
this.expensesRequestFactory = expensesRequestFactory;
createErrorPopup();
initTable();
@@ -506,23 +467,20 @@
});
}
+ public ReportListPlace getReportListPlace() {
+ ReportListPlace listPlace = place.getListPlace();
+ return listPlace == null ? ReportListPlace.ALL : listPlace;
+ }
+
public Anchor getReportsLink() {
return reportsLink;
}
- public void init(EventBus eventBus) {
- EntityProxyChange.registerForProxyType(eventBus, ExpenseProxy.class,
- new EntityProxyChange.Handler<ExpenseProxy>() {
- public void onProxyChange(EntityProxyChange<ExpenseProxy> event) {
- onExpenseRecordChanged(event);
- }
- });
- EntityProxyChange.registerForProxyType(eventBus, ReportProxy.class,
- new EntityProxyChange.Handler<ReportProxy>() {
- public void onProxyChange(EntityProxyChange<ReportProxy> event) {
- onReportChanged(event);
- }
- });
+ public String mayStop() {
+ return null;
+ }
+
+ public void onCancel() {
}
public void onExpenseRecordChanged(EntityProxyChange<ExpenseProxy> event) {
@@ -571,42 +529,57 @@
}
}
- /**
- * Set the {@link ReportProxy} to show.
- *
- * @param report the {@link ReportProxy}
- * @param department the selected department
- * @param employee the selected employee
- */
- public void setReportRecord(ReportProxy report, String department,
- EmployeeProxy employee) {
- this.report = report;
- knownExpenseKeys = null;
- reportName.setInnerText(report.getPurpose());
- costLabel.setInnerText("");
- approvedLabel.setInnerText("");
- unreconciledLabel.setInnerText("");
- setNotesEditState(false, false, report.getNotes());
- items.getList().clear();
- totalApproved = 0;
+ public void onStop() {
+ }
- // Update the breadcrumb.
- reportsLink.setText(ExpenseList.getBreadcrumb(department, employee));
+ public void start(AcceptsOneWidget panel, EventBus eventBus) {
+ final ReportListPlace listPlace = place.getListPlace();
- // Reset sorting state of table
- lastComparator = defaultComparator;
- if (allHeaders.size() > 0) {
- for (SortableHeader header : allHeaders) {
- header.setSorted(false);
- header.setReverseSort(true);
- }
- allHeaders.get(0).setSorted(true);
- allHeaders.get(0).setReverseSort(false);
- table.redrawHeaders();
+ if (listPlace.getEmployeeId() == null) {
+ expensesRequestFactory.find(place.getReportId()).fire(
+ new Receiver<ReportProxy>() {
+ @Override
+ public void onSuccess(ReportProxy response) {
+ setReportRecord(response, listPlace.getDepartment(), null);
+ }
+ });
+ } else {
+ new EmployeeReportFetcher().Run(listPlace.getEmployeeId(),
+ place.getReportId(),
+ new Receiver<ExpenseReportDetails.EmployeeReportFetcher>() {
+ @Override
+ public void onSuccess(EmployeeReportFetcher response) {
+ setReportRecord(response.fetchedReport,
+ listPlace.getDepartment(), response.fetchedEmployee);
+ }
+ });
}
- // Request the expenses.
- requestExpenses();
+ EntityProxyChange.registerForProxyType(eventBus, ExpenseProxy.class,
+ new EntityProxyChange.Handler<ExpenseProxy>() {
+ public void onProxyChange(EntityProxyChange<ExpenseProxy> event) {
+ onExpenseRecordChanged(event);
+ }
+ });
+
+ EntityProxyChange.registerForProxyType(eventBus, ReportProxy.class,
+ new EntityProxyChange.Handler<ReportProxy>() {
+ public void onProxyChange(EntityProxyChange<ReportProxy> event) {
+ onReportChanged(event);
+ }
+ });
+
+ panel.setWidget(this);
+ }
+
+ /**
+ * In this application, called by {@link ExpensesActivityMapper} each time a
+ * ReportListPlace is posted. In a more typical set up, this would be a
+ * constructor argument to a one shot activity, perhaps managing a shared
+ * widget view instance.
+ */
+ public void updateForPlace(final ReportPlace place) {
+ this.place = place;
}
/**
@@ -996,6 +969,44 @@
}
/**
+ * Set the {@link ReportProxy} to show.
+ *
+ * @param report the {@link ReportProxy}
+ * @param department the selected department, or ""
+ * @param employee the selected employee, or null
+ */
+ private void setReportRecord(ReportProxy report, String department,
+ EmployeeProxy employee) {
+ this.report = report;
+ knownExpenseKeys = null;
+ reportName.setInnerText(report.getPurpose());
+ costLabel.setInnerText("");
+ approvedLabel.setInnerText("");
+ unreconciledLabel.setInnerText("");
+ setNotesEditState(false, false, report.getNotes());
+ items.getList().clear();
+ totalApproved = 0;
+
+ // Update the breadcrumb.
+ reportsLink.setText(ExpenseReportList.getBreadcrumb(department, employee));
+
+ // Reset sorting state of table
+ lastComparator = defaultComparator;
+ if (allHeaders.size() > 0) {
+ for (SortableHeader header : allHeaders) {
+ header.setSorted(false);
+ header.setReverseSort(true);
+ }
+ allHeaders.get(0).setSorted(true);
+ allHeaders.get(0).setReverseSort(false);
+ table.redrawHeaders();
+ }
+
+ // Request the expenses.
+ requestExpenses();
+ }
+
+ /**
* Show the error popup.
*
* @param errorMessage the error message
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseDetails.ui.xml b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.ui.xml
similarity index 100%
rename from samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseDetails.ui.xml
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.ui.xml
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseList.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java
similarity index 86%
rename from samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseList.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java
index c0f0c40..bb40add 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseList.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.sample.expenses.client;
+import com.google.gwt.activity.shared.Activity;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.DateCell;
@@ -40,9 +41,9 @@
import com.google.gwt.requestfactory.ui.client.EntityProxyKeyProvider;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+import com.google.gwt.sample.expenses.client.place.ReportListPlace;
import com.google.gwt.sample.expenses.client.style.Styles;
import com.google.gwt.sample.expenses.shared.EmployeeProxy;
-import com.google.gwt.sample.expenses.shared.ExpenseProxy;
import com.google.gwt.sample.expenses.shared.ExpensesRequestFactory;
import com.google.gwt.sample.expenses.shared.ReportProxy;
import com.google.gwt.uibinder.client.UiBinder;
@@ -50,19 +51,19 @@
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
-import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
+import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.view.client.AsyncDataProvider;
-import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.NoSelectionModel;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.Range;
+import com.google.gwt.view.client.RangeChangeEvent;
import com.google.gwt.view.client.SelectionChangeEvent;
import java.util.ArrayList;
@@ -74,10 +75,10 @@
/**
* The list of expense reports on the right side of the app.
*/
-public class ExpenseList extends Composite implements
- EntityProxyChange.Handler<ReportProxy> {
+public class ExpenseReportList extends Composite implements
+ EntityProxyChange.Handler<ReportProxy>, Activity {
- interface ExpenseListUiBinder extends UiBinder<Widget, ExpenseList> {
+ interface Binder extends UiBinder<Widget, ExpenseReportList> {
}
/**
@@ -175,27 +176,15 @@
}
}
}
- /**
- * The data provider used to retrieve reports.
- */
- private class ReportDataProvider extends AsyncDataProvider<ReportProxy> {
- ReportDataProvider(ProvidesKey<ReportProxy> keyProvider) {
- super(keyProvider);
- }
-
- @Override
- protected void onRangeChanged(HasData<ReportProxy> display) {
- requestReports(false);
- }
- }
+ private static final ProvidesKey<ReportProxy> keyProvider = new EntityProxyKeyProvider<ReportProxy>();
/**
* The auto refresh interval in milliseconds.
*/
private static final int REFRESH_INTERVAL = 5000;
- private static ExpenseListUiBinder uiBinder = GWT.create(ExpenseListUiBinder.class);
+ private static Binder uiBinder = GWT.create(Binder.class);
/**
* Utility method to get the first part of the breadcrumb based on the
@@ -206,9 +195,10 @@
* @return the breadcrumb
*/
public static String getBreadcrumb(String department, EmployeeProxy employee) {
+ assert null != department;
if (employee != null) {
return "Reports for " + employee.getDisplayName();
- } else if (department != null) {
+ } else if (!"".equals(department)) {
return "Reports for " + department;
} else {
return "All Reports";
@@ -217,13 +207,14 @@
@UiField
Element breadcrumb;
-
@UiField
SimplePager pager;
- @UiField(provided = true)
- DefaultTextBox searchBox;
@UiField
Image searchButton;
+
+ @UiField(provided = true)
+ DefaultTextBox searchBox;
+
/**
* The main table. We provide this in the constructor before calling
* {@link UiBinder#createAndBindUi(Object)} because the pager depends on it.
@@ -289,15 +280,9 @@
"created", "purpose", "notes"};
/**
- * The data provider that provides reports.
- */
- private final ReportDataProvider reports = new ReportDataProvider(
- new EntityProxyKeyProvider<ReportProxy>());
-
- /**
* The factory used to send requests.
*/
- private ExpensesRequestFactory requestFactory;
+ private final ExpensesRequestFactory requestFactory;
/**
* The string that the user searched for.
@@ -309,15 +294,23 @@
*/
private String startsWithSearch;
- public ExpenseList() {
+ private ReportListPlace place;
+
+ private boolean running;
+
+ public ExpenseReportList(ExpensesRequestFactory requestFactory) {
+ this.requestFactory = requestFactory;
+
// Initialize the widget.
createTable();
+ table.addRangeChangeHandler(new RangeChangeEvent.Handler() {
+ public void onRangeChange(RangeChangeEvent event) {
+ requestReports(false);
+ }
+ });
searchBox = new DefaultTextBox("search");
initWidget(uiBinder.createAndBindUi(this));
- // Add the view to the data provider.
- reports.addDataDisplay(table);
-
// Listen for key events from the text boxes.
searchBox.addKeyUpHandler(new KeyUpHandler() {
public void onKeyUp(KeyUpEvent event) {
@@ -344,10 +337,12 @@
});
}
- public void init(ExpensesRequestFactory factory, EventBus eventBus) {
- EntityProxyChange.registerForProxyType(eventBus, ReportProxy.class, this);
- this.requestFactory = factory;
- requestReports(false);
+ public String mayStop() {
+ return null;
+ }
+
+ public void onCancel() {
+ onStop();
}
public void onProxyChange(EntityProxyChange<ReportProxy> event) {
@@ -358,36 +353,43 @@
if (record != null && changedId.equals(record.stableId())) {
List<ReportProxy> changedList = new ArrayList<ReportProxy>();
changedList.add(record);
- reports.updateRowData(i + table.getPageStart(), changedList);
+ table.setRowData(i + table.getPageStart(), changedList);
}
i++;
}
}
- /**
- * Set the current department and employee to filter on.
- *
- * @param department the department, or null if none selected
- * @param employee the employee, or null if none selected
- */
- public void setEmployee(String department, EmployeeProxy employee) {
- this.department = department;
- this.employee = employee;
- isCountStale = true;
- searchBox.resetDefaultText();
- startsWithSearch = null;
- breadcrumb.setInnerText(getBreadcrumb(department, employee));
- searchRegExp = null;
-
- // Refresh the table.
- pager.setPageStart(0);
- requestReports(false);
+ public void onStop() {
+ running = false;
+ refreshTimer.cancel();
}
public void setListener(Listener listener) {
this.listener = listener;
}
+ public void start(AcceptsOneWidget panel, EventBus eventBus) {
+ running = true;
+ doUpdateForPlace();
+
+ EntityProxyChange.registerForProxyType(eventBus, ReportProxy.class, this);
+ requestReports(false);
+ panel.setWidget(this);
+ }
+
+ /**
+ * In this application, called by {@link ExpensesActivityMapper} each time a
+ * ReportListPlace is posted. In a more typical set up, this would be a
+ * constructor argument to a one shot activity, perhaps managing a shared
+ * widget view instance.
+ */
+ public void updateForPlace(final ReportListPlace place) {
+ this.place = place;
+ if (running) {
+ doUpdateForPlace();
+ }
+ }
+
@UiFactory
SimplePager createPager() {
SimplePager p = new SimplePager(TextLocation.RIGHT);
@@ -520,6 +522,39 @@
table.addColumn(new SpacerColumn<ReportProxy>());
}
+ private void doUpdateForPlace() {
+ if (place.getEmployeeId() == null) {
+ findDepartmentOrEmployee(place.getDepartment(), null);
+ } else {
+ requestFactory.find(place.getEmployeeId()).fire(
+ new Receiver<EmployeeProxy>() {
+ @Override
+ public void onSuccess(EmployeeProxy response) {
+ findDepartmentOrEmployee("", response);
+ }
+ });
+ }
+ }
+
+ /**
+ * Set the current department and employee to filter on.
+ *
+ * @param department the department, or null if none selected
+ * @param employee the employee, or null if none selected
+ */
+ private void findDepartmentOrEmployee(String department,
+ EmployeeProxy employee) {
+ this.department = department;
+ this.employee = employee;
+ isCountStale = true;
+ searchBox.resetDefaultText();
+ startsWithSearch = null;
+ breadcrumb.setInnerText(getBreadcrumb(department, employee));
+ searchRegExp = null;
+ pager.setPageStart(0);
+ requestReports(false);
+ }
+
/**
* Send a request for reports in the current range.
*
@@ -569,7 +604,7 @@
if (this == lastDataSizeReceiver) {
int count = response.intValue();
// Treat count == 1000 as inexact due to AppEngine limitation
- reports.updateRowCount(count, count != 1000);
+ table.setRowCount(count, count != 1000);
}
}
};
@@ -585,10 +620,10 @@
int size = newValues.size();
if (size < table.getPageSize()) {
// Now we know the exact data size
- reports.updateRowCount(table.getPageStart() + size, true);
+ table.setRowCount(table.getPageStart() + size, true);
}
if (size > 0) {
- reports.updateRowData(table.getPageStart(), newValues);
+ table.setRowData(table.getPageStart(), newValues);
}
// Add the new keys to the known keys.
@@ -597,10 +632,10 @@
knownReportKeys = new HashSet<Object>();
}
for (ReportProxy value : newValues) {
- Object key = reports.getKey(value);
+ Object key = keyProvider.getKey(value);
if (!isInitialData && !knownReportKeys.contains(key)) {
- (new PhaseAnimation.CellTablePhaseAnimation<ReportProxy>(table,
- value, reports)).run();
+ new PhaseAnimation.CellTablePhaseAnimation<ReportProxy>(table,
+ value, keyProvider).run();
}
knownReportKeys.add(key);
}
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseList.ui.xml b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.ui.xml
similarity index 100%
rename from samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseList.ui.xml
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.ui.xml
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java
index 556a83b..49d29be 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java
@@ -21,9 +21,11 @@
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Overflow;
+import com.google.gwt.requestfactory.shared.EntityProxyId;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.ui.client.EntityProxyKeyProvider;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
+import com.google.gwt.safehtml.client.SafeHtmlTemplates.Template;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.sample.expenses.client.style.Styles;
@@ -58,7 +60,7 @@
* @param department the selected department name
* @param employee the selected employee
*/
- void onSelection(String department, EmployeeProxy employee);
+ void onSelection(String department, EntityProxyId<EmployeeProxy> employeeId);
}
interface Template extends SafeHtmlTemplates {
@@ -251,7 +253,7 @@
public ExpenseTree(ExpensesRequestFactory requestFactory) {
this.requestFactory = requestFactory;
-
+
// Initialize the departments.
List<String> departmentList = departments.getList();
departmentList.add("All");
@@ -282,20 +284,21 @@
Object selected = selectionModel.getSelectedObject();
if (selected == null) {
lastEmployee = null;
- lastDepartment = null;
+ lastDepartment = "";
} else if (selected instanceof EmployeeProxy) {
lastEmployee = (EmployeeProxy) selected;
} else if (selected instanceof String) {
lastEmployee = null;
if (model.isAllDepartment(selected)) {
- lastDepartment = null;
+ lastDepartment = "";
} else {
lastDepartment = (String) selected;
}
}
if (listener != null) {
- listener.onSelection(lastDepartment, lastEmployee);
+ listener.onSelection(lastDepartment, lastEmployee == null ? null
+ : lastEmployee.stableId());
}
}
});
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/Expenses.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/Expenses.java
index c4a66a7..c04cca8 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/Expenses.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/Expenses.java
@@ -16,7 +16,7 @@
package com.google.gwt.sample.expenses.client;
import com.google.gwt.core.client.EntryPoint;
-import com.google.gwt.sample.expenses.client.ioc.Factory;
+import com.google.gwt.sample.expenses.client.ioc.ExpensesFactory;
import com.google.gwt.user.client.ui.RootLayoutPanel;
/**
@@ -25,6 +25,6 @@
public class Expenses implements EntryPoint {
public void onModuleLoad() {
- new Factory().getExpensesApp().run(RootLayoutPanel.get());
+ new ExpensesFactory().getExpensesApp().run(RootLayoutPanel.get());
}
}
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesActivityMapper.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesActivityMapper.java
new file mode 100644
index 0000000..ed58976
--- /dev/null
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesActivityMapper.java
@@ -0,0 +1,51 @@
+/*
+ * 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.expenses.client;
+
+import com.google.gwt.activity.shared.Activity;
+import com.google.gwt.activity.shared.ActivityMapper;
+import com.google.gwt.place.shared.Place;
+import com.google.gwt.sample.expenses.client.place.ReportListPlace;
+import com.google.gwt.sample.expenses.client.place.ReportPlace;
+
+/**
+ * ActivityMapper for the Expenses app.
+ */
+public class ExpensesActivityMapper implements ActivityMapper {
+
+ private final ExpenseReportDetails expenseDetails;
+ private final ExpenseReportList expenseList;
+
+ public ExpensesActivityMapper(ExpenseReportDetails expenseDetails,
+ ExpenseReportList expenseList) {
+ this.expenseDetails = expenseDetails;
+ this.expenseList = expenseList;
+ }
+
+ public Activity getActivity(Place place) {
+ if (place instanceof ReportListPlace) {
+ expenseList.updateForPlace((ReportListPlace) place);
+ return expenseList;
+ }
+
+ if (place instanceof ReportPlace) {
+ expenseDetails.updateForPlace((ReportPlace) place);
+ return expenseDetails;
+ }
+
+ return null;
+ }
+}
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesApp.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesApp.java
index 63625d0..0975f0a 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesApp.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesApp.java
@@ -15,16 +15,21 @@
*/
package com.google.gwt.sample.expenses.client;
+import com.google.gwt.activity.shared.ActivityManager;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.EventBus;
-import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.place.shared.PlaceHistoryHandler;
+import com.google.gwt.requestfactory.shared.EntityProxyId;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.shared.RequestEvent;
import com.google.gwt.requestfactory.shared.UserInformationProxy;
import com.google.gwt.requestfactory.ui.client.AuthenticationFailureHandler;
import com.google.gwt.requestfactory.ui.client.LoginWidget;
+import com.google.gwt.sample.expenses.client.place.ReportListPlace;
+import com.google.gwt.sample.expenses.client.place.ReportPlace;
import com.google.gwt.sample.expenses.shared.EmployeeProxy;
import com.google.gwt.sample.expenses.shared.ExpensesRequestFactory;
import com.google.gwt.sample.expenses.shared.ReportProxy;
@@ -46,23 +51,25 @@
private static final Logger log = Logger.getLogger(ExpensesShell.class.getName());
+ private final ActivityManager activityManager;
private final EventBus eventBus;
private final PlaceController placeController;
private final PlaceHistoryHandler placeHistoryHandler;
private final ExpensesRequestFactory requestFactory;
private final ExpensesShell shell;
- private String lastDepartment;
- private EmployeeProxy lastEmployee;
+ private EntityProxyId<EmployeeProxy> lastEmployee;
+ private String lastDepartment = "";
- public ExpensesApp(ExpensesRequestFactory requestFactory, EventBus eventBus,
- ExpensesShell shell, PlaceHistoryHandler placeHistoryHandler,
- PlaceController placeController) {
- this.requestFactory = requestFactory;
+ public ExpensesApp(ActivityManager activityManager, EventBus eventBus,
+ PlaceController placeController, PlaceHistoryHandler placeHistoryHandler,
+ ExpensesRequestFactory requestFactory, ExpensesShell shell) {
+ this.activityManager = activityManager;
this.eventBus = eventBus;
- this.shell = shell;
- this.placeHistoryHandler = placeHistoryHandler;
this.placeController = placeController;
+ this.placeHistoryHandler = placeHistoryHandler;
+ this.requestFactory = requestFactory;
+ this.shell = shell;
}
/**
@@ -76,10 +83,15 @@
});
final ExpenseTree expenseTree = shell.getExpenseTree();
- final ExpenseList expenseList = shell.getExpenseList();
- final ExpenseDetails expenseDetails = shell.getExpenseDetails();
+ final ExpenseReportList expenseList = shell.getExpenseList();
+ final ExpenseReportDetails expenseDetails = shell.getExpenseDetails();
- root.add(shell);
+ // Handle breadcrumb events from Expense Details.
+ expenseDetails.getReportsLink().addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ placeController.goTo(expenseDetails.getReportListPlace());
+ }
+ });
// Check for Authentication failures or mismatches
RequestEvent.register(eventBus, new AuthenticationFailureHandler());
@@ -97,32 +109,31 @@
// Listen for requests from ExpenseTree.
expenseTree.setListener(new ExpenseTree.Listener() {
- public void onSelection(String department, EmployeeProxy employee) {
- lastDepartment = department;
+
+ public void onSelection(String department, EntityProxyId<EmployeeProxy> employee) {
lastEmployee = employee;
- expenseList.setEmployee(department, employee);
- shell.showExpenseDetails(false);
+ lastDepartment = department;
+ placeController.goTo(new ReportListPlace(employee, department));
}
});
// Listen for requests from the ExpenseList.
- expenseList.setListener(new ExpenseList.Listener() {
+ expenseList.setListener(new ExpenseReportList.Listener() {
public void onReportSelected(ReportProxy report) {
- expenseDetails.setReportRecord(report, lastDepartment, lastEmployee);
- shell.showExpenseDetails(true);
+ placeController.goTo(new ReportPlace( //
+ new ReportListPlace(lastEmployee, lastDepartment), //
+ report.stableId() //
+ ));
}
});
- /*
- * TODO these should be constructor arguments, and the inits should probably
- * happen onLoad
- */
- expenseList.init(requestFactory, eventBus);
- expenseDetails.init(eventBus);
+ // Give the ActivityManager a panel to run
+ activityManager.setDisplay(shell.getPanel());
// Browser history integration
- placeHistoryHandler.register(placeController, eventBus, new Place() {
- });
+ placeHistoryHandler.register(placeController, eventBus, ReportListPlace.ALL);
placeHistoryHandler.handleCurrentHistory();
+
+ root.add(shell);
}
}
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.java
index 0e79d0f..bee5035 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.java
@@ -16,13 +16,12 @@
package com.google.gwt.sample.expenses.client;
import com.google.gwt.core.client.GWT;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.requestfactory.ui.client.LoginWidget;
import com.google.gwt.uibinder.client.UiBinder;
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.HasOneWidget;
import com.google.gwt.user.client.ui.Widget;
/**
@@ -34,37 +33,31 @@
private static ShellUiBinder uiBinder = GWT.create(ShellUiBinder.class);
- @UiField
- ExpenseList expenseList;
+ @UiField(provided = true)
+ final ExpenseReportList expenseList;
+
+ @UiField(provided = true)
+ final ExpenseReportDetails expenseDetails;
+
@UiField(provided = true)
final ExpenseTree expenseTree;
- @UiField
- SlidingPanel slidingPanel;
- @UiField
- LoginWidget loginWidget;
- @UiField
- DockLayoutPanel dockLayout;
- @UiField(provided = true)
- final ExpenseDetails expenseDetails;
+
+ @UiField SlidingPanel slidingPanel;
+ @UiField LoginWidget loginWidget;
+ @UiField DockLayoutPanel dockLayout;
- public ExpensesShell(ExpenseTree expenseTree, ExpenseDetails expenseDetails) {
+ public ExpensesShell(ExpenseTree expenseTree, ExpenseReportList expenseList, ExpenseReportDetails expenseDetails) {
this.expenseTree = expenseTree;
+ this.expenseList = expenseList;
this.expenseDetails = expenseDetails;
initWidget(uiBinder.createAndBindUi(this));
-
- // Handle breadcrumb events from Expense Details.
- expenseDetails.getReportsLink().addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
- showExpenseDetails(false);
- }
- });
}
- public ExpenseDetails getExpenseDetails() {
+ public ExpenseReportDetails getExpenseDetails() {
return expenseDetails;
}
- public ExpenseList getExpenseList() {
+ public ExpenseReportList getExpenseList() {
return expenseList;
}
@@ -72,19 +65,11 @@
return expenseTree;
}
- /**
- * @return the login widget
- */
public LoginWidget getLoginWidget() {
return loginWidget;
}
- /**
- * Show or hide the expense details. When showing, the expense list is hidden.
- *
- * @param isShowing true to show details, false to show reports list
- */
- public void showExpenseDetails(boolean isShowing) {
- slidingPanel.setWidget(isShowing ? expenseDetails : expenseList);
+ public HasOneWidget getPanel() {
+ return slidingPanel;
}
}
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.ui.xml b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.ui.xml
index bd54c12..a146dbd 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.ui.xml
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpensesShell.ui.xml
@@ -68,8 +68,8 @@
<g:center>
<e:SlidingPanel ui:field='slidingPanel'>
<!-- The order of the children determines which way they slide -->
- <e:ExpenseList ui:field='expenseList' />
- <e:ExpenseDetails ui:field='expenseDetails' />
+ <e:ExpenseReportList ui:field='expenseList' />
+ <e:ExpenseReportDetails ui:field='expenseDetails' />
</e:SlidingPanel>
</g:center>
</g:DockLayoutPanel>
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SlidingPanel.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SlidingPanel.java
index 6b8d18b..95a422c 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SlidingPanel.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SlidingPanel.java
@@ -50,7 +50,7 @@
}
public void add(IsWidget w) {
- add(w.asWidget());
+ add(asWidgetOrNull(w.asWidget()));
}
public void add(Widget w) {
@@ -82,12 +82,20 @@
}
public void setWidget(IsWidget w) {
- setWidget(w.asWidget());
+ setWidget(asWidgetOrNull(w));
}
+ /**
+ * Set the widget to show, adding it to the end of our sliding set if we
+ * haven't seen it before. Nulls are ignored.
+ */
// Conflict btw deprecated Composite#setWidget and HasOneWidget#setWidget
@SuppressWarnings("deprecation")
public void setWidget(Widget widget) {
+ if (widget == null) {
+ return;
+ }
+
int newIndex = widgets.indexOf(widget);
if (newIndex < 0) {
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ioc/Factory.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ioc/ExpensesFactory.java
similarity index 60%
rename from samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ioc/Factory.java
rename to samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ioc/ExpensesFactory.java
index f2dfc9e..aa5ec92 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ioc/Factory.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ioc/ExpensesFactory.java
@@ -15,13 +15,17 @@
*/
package com.google.gwt.sample.expenses.client.ioc;
+import com.google.gwt.activity.shared.ActivityManager;
+import com.google.gwt.activity.shared.ActivityMapper;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.place.shared.PlaceHistoryHandler;
-import com.google.gwt.sample.expenses.client.ExpenseDetails;
+import com.google.gwt.sample.expenses.client.ExpenseReportDetails;
+import com.google.gwt.sample.expenses.client.ExpenseReportList;
import com.google.gwt.sample.expenses.client.ExpenseTree;
+import com.google.gwt.sample.expenses.client.ExpensesActivityMapper;
import com.google.gwt.sample.expenses.client.ExpensesApp;
import com.google.gwt.sample.expenses.client.ExpensesShell;
import com.google.gwt.sample.expenses.client.place.ExpensesPlaceHistoryMapper;
@@ -34,30 +38,50 @@
* <p>
* TODO: Use {@link http ://code.google.com/p/google-gin/} to generate this
*/
-public class Factory {
+public class ExpensesFactory {
private final EventBus eventBus = new SimpleEventBus();
private final ExpensesRequestFactory requestFactory = GWT.create(ExpensesRequestFactory.class);
private final ExpensesPlaceHistoryMapper historyMapper = GWT.create(ExpensesPlaceHistoryMapper.class);
private final PlaceHistoryHandler placeHistoryHandler;
private final PlaceController placeController = new PlaceController(eventBus);
+ private final ExpenseTree expenseTree = new ExpenseTree(requestFactory);
+ private final ExpenseReportList expenseList = new ExpenseReportList(requestFactory);
+ private final ExpenseReportDetails expenseDetails = new ExpenseReportDetails(
+ requestFactory);
+ private final ActivityMapper activityMapper = new ExpensesActivityMapper(
+ expenseDetails, expenseList);
+ private final ActivityManager activityManager = new ActivityManager(
+ activityMapper, eventBus);
- public Factory() {
+ public ExpensesFactory() {
requestFactory.initialize(eventBus);
historyMapper.setFactory(this);
placeHistoryHandler = new PlaceHistoryHandler(historyMapper);
}
public ExpensesApp getExpensesApp() {
- return new ExpensesApp(requestFactory, eventBus, new ExpensesShell(
- new ExpenseTree(requestFactory), new ExpenseDetails(requestFactory)),
- placeHistoryHandler, placeController);
+ return new ExpensesApp(activityManager, eventBus, placeController,
+ placeHistoryHandler, requestFactory, new ExpensesShell(expenseTree,
+ expenseList, expenseDetails));
}
+ /**
+ * Exposed for generated {@link ExpensesPlaceHistoryMapper}, which creates a
+ * bookmarkable place in the app for each type of
+ * {@link com.google.gwt.place.shared.PlaceTokenizer} it can find in the
+ * factory.
+ */
public ReportListPlace.Tokenizer getListTokenizer() {
return new ReportListPlace.Tokenizer(requestFactory);
}
+ /**
+ * Exposed for generated {@link ExpensesPlaceHistoryMapper}, which creates a
+ * bookmarkable place in the app for each type of
+ * {@link com.google.gwt.place.shared.PlaceTokenizer} it can find in the
+ * factory.
+ */
public ReportPlace.Tokenizer getReportTokenizer() {
return new ReportPlace.Tokenizer(getListTokenizer(), requestFactory);
}
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ExpensesPlaceHistoryMapper.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ExpensesPlaceHistoryMapper.java
index d5d16de..eae962a 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ExpensesPlaceHistoryMapper.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ExpensesPlaceHistoryMapper.java
@@ -16,7 +16,7 @@
package com.google.gwt.sample.expenses.client.place;
import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;
-import com.google.gwt.sample.expenses.client.ioc.Factory;
+import com.google.gwt.sample.expenses.client.ioc.ExpensesFactory;
/**
* This interface is the hub of your application's navigation system. It links
@@ -31,17 +31,17 @@
* annotation below and list their corresponding
* {@link com.google.gwt.place.shared.PlaceTokenizer PlaceTokenizer}s. Or if a
* tokenizer needs more than a default constructor can provide, add a method to
- * the apps {@link Factory}.
+ * the apps {@link ExpensesFactory}.
*
* <p>
* This code generated object looks to both the {@literal @}WithTokenizers
* annotation and the factory to infer the types of
* {@link com.google.gwt.place.Place Place}s your app can navigate to. In this
- * case it will find the {@link Factory#getListTokenizer()} and
- * {@link Factory#getReportTokenizer()} methods, and so be able to handle
+ * case it will find the {@link ExpensesFactory#getListTokenizer()} and
+ * {@link ExpensesFactory#getReportTokenizer()} methods, and so be able to handle
* {@link ReportListPlace}s and {@link ReportPlace}s.
*/
// @WithTokenizers({MyNewPlace.Tokenizer, MyOtherNewPlace.Tokenizer})
public interface ExpensesPlaceHistoryMapper extends
- PlaceHistoryMapperWithFactory<Factory> {
+ PlaceHistoryMapperWithFactory<ExpensesFactory> {
}
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ReportListPlace.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ReportListPlace.java
index 0f513c1..b260de2 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ReportListPlace.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ReportListPlace.java
@@ -29,11 +29,13 @@
public class ReportListPlace extends Place {
/**
- * Tokenizer.
+ * Tokenizer, which by all rights should have been code generated. Stay tuned.
*/
@Prefix("l")
public static class Tokenizer implements PlaceTokenizer<ReportListPlace> {
static final String SEPARATOR = "!";
+ private static final String NO_ID = "n";
+
private final RequestFactory requests;
public Tokenizer(RequestFactory requests) {
@@ -43,43 +45,47 @@
public ReportListPlace getPlace(String token) {
String bits[] = token.split(SEPARATOR);
- if (bits.length != 3) {
+ if (bits.length != 2) {
return null;
}
- String reporterIdToken = bits[0];
- String search = bits[1];
- int page = Integer.valueOf(bits[2]);
+ String department = URL.decodePathSegment(bits[0]);
+ String reporterIdToken = bits[1];
- return new ReportListPlace(requests.<EmployeeProxy> getProxyId(reporterIdToken),
- URL.decodePathSegment(search), page);
+ EntityProxyId<EmployeeProxy> proxyId = NO_ID.equals(reporterIdToken)
+ ? null : requests.<EmployeeProxy> getProxyId(reporterIdToken);
+ return new ReportListPlace(proxyId, department);
}
public String getToken(ReportListPlace place) {
- return requests.getHistoryToken(place.getReporterId()) + SEPARATOR
- + URL.encodePathSegment(place.getSearch());
+ EntityProxyId<EmployeeProxy> id = place.getEmployeeId();
+ String idToken = id == null ? NO_ID : requests.getHistoryToken(id);
+ return URL.encodePathSegment(place.getDepartment()) + SEPARATOR + idToken;
}
}
- private final int page;
- private final EntityProxyId<EmployeeProxy> reporterId;
- private final String search;
+ public static final ReportListPlace ALL = new ReportListPlace(null, "");
- public ReportListPlace(EntityProxyId<EmployeeProxy> reporter, String search, int page) {
- this.reporterId = reporter;
- this.search = search;
- this.page = page;
+ private final EntityProxyId<EmployeeProxy> employeeId;
+ private final String department;
+
+ public ReportListPlace(EntityProxyId<EmployeeProxy> employeeId,
+ String department) {
+ this.employeeId = employeeId;
+ this.department = department;
}
- public int getPage() {
- return page;
- }
-
- public EntityProxyId<EmployeeProxy> getReporterId() {
- return reporterId;
+ /**
+ * @return the department searched for, or null for none
+ */
+ public String getDepartment() {
+ return department;
}
- public String getSearch() {
- return search;
+ /**
+ * @return the employee to focus on, or null for none
+ */
+ public EntityProxyId<EmployeeProxy> getEmployeeId() {
+ return employeeId;
}
}
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ReportPlace.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ReportPlace.java
index a8c42f8..243d7f2 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ReportPlace.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/place/ReportPlace.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.sample.expenses.client.place;
+import static com.google.gwt.sample.expenses.client.place.ReportListPlace.Tokenizer.SEPARATOR;
+
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceTokenizer;
import com.google.gwt.place.shared.Prefix;
@@ -41,30 +43,26 @@
this.listTokenizer = listTokenizer;
}
- private static final String SEPARATOR = ReportListPlace.Tokenizer.SEPARATOR
- + ReportListPlace.Tokenizer.SEPARATOR;
-
public ReportPlace getPlace(String token) {
- String[] bits = token.split(SEPARATOR);
- if (bits.length != 2) {
+ int i = token.indexOf(SEPARATOR);
+ if (i < 0) {
return null;
}
- String listPlaceToken = bits[0];
- String reporterToken = bits[1];
-
+ String reporterToken = token.substring(0, i);
+ String listPlaceToken = token.substring(i + SEPARATOR.length());
+
return new ReportPlace(listTokenizer.getPlace(listPlaceToken),
requests.<ReportProxy> getProxyId(reporterToken));
}
public String getToken(ReportPlace place) {
- return listTokenizer.getToken(place.getListPlace()) + SEPARATOR
- + requests.getHistoryToken(place.getReportId());
+ return requests.getHistoryToken(place.getReportId()) + SEPARATOR
+ + listTokenizer.getToken(place.getListPlace());
}
}
private final ReportListPlace listPlace;
-
private final EntityProxyId<ReportProxy> reportId;
public ReportPlace(ReportListPlace listPlace,
@@ -80,4 +78,35 @@
public EntityProxyId<ReportProxy> getReportId() {
return reportId;
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((listPlace == null) ? 0 : listPlace.hashCode());
+ result = prime * result + ((reportId == null) ? 0 : reportId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ReportPlace other = (ReportPlace) obj;
+ if (listPlace == null) {
+ if (other.listPlace != null)
+ return false;
+ } else if (!listPlace.equals(other.listPlace))
+ return false;
+ if (reportId == null) {
+ if (other.reportId != null)
+ return false;
+ } else if (!reportId.equals(other.reportId))
+ return false;
+ return true;
+ }
}
diff --git a/user/src/com/google/gwt/place/shared/PlaceHistoryHandler.java b/user/src/com/google/gwt/place/shared/PlaceHistoryHandler.java
index 94fa17f..51aa52f 100644
--- a/user/src/com/google/gwt/place/shared/PlaceHistoryHandler.java
+++ b/user/src/com/google/gwt/place/shared/PlaceHistoryHandler.java
@@ -25,7 +25,8 @@
import java.util.logging.Logger;
/**
- * Monitors {@link PlaceChangeEvent}s and {@link com.google.gwt.user.client.History} events and keep them in sync.
+ * Monitors {@link PlaceChangeEvent}s and
+ * {@link com.google.gwt.user.client.History} events and keep them in sync.
*/
public class PlaceHistoryHandler {
private static final Logger log = Logger.getLogger(PlaceHistoryHandler.class.getName());
@@ -51,16 +52,29 @@
/**
* Optional delegate in charge of History related events. Provides nice
* isolation for unit testing, and allows pre- or post-processing of tokens.
+ * Methods correspond to the like named methods on {@link History}.
*/
public interface Historian {
- // TODO - document
+ /**
+ * Adds a {@link com.google.gwt.event.logical.shared.ValueChangeEvent}
+ * handler to be informed of changes to the browser's history stack.
+ *
+ * @param handler the handler
+ * @return the registration used to remove this value change handler
+ */
HandlerRegistration addValueChangeHandler(
ValueChangeHandler<String> valueChangeHandler);
- // TODO - document
+ /**
+ * @return the current history token.
+ */
String getToken();
- // TODO - document
+ /**
+ * Adds a new browser history entry. Calling this method will cause
+ * {@link ValueChangeHandler#onValueChange(com.google.gwt.event.logical.shared.ValueChangeEvent)}
+ * to be called as well.
+ */
void newItem(String token, boolean issueEvent);
}
@@ -73,11 +87,11 @@
private Place defaultPlace = Place.NOWHERE;
/**
- * Create a new PlaceHistoryHandler with a {@link DefaultHistorian}.
- * The DefaultHistorian is created via a call to GWT.create(), so an
- * alternative default implementation can be provided through
- * <replace-with> rules in a {@code gwt.xml} file.
- *
+ * Create a new PlaceHistoryHandler with a {@link DefaultHistorian}. The
+ * DefaultHistorian is created via a call to GWT.create(), so an alternative
+ * default implementation can be provided through <replace-with> rules
+ * in a {@code gwt.xml} file.
+ *
* @param mapper a {@link PlaceHistoryMapper} instance
*/
public PlaceHistoryHandler(PlaceHistoryMapper mapper) {
@@ -86,7 +100,7 @@
/**
* Create a new PlaceHistoryHandler.
- *
+ *
* @param mapper a {@link PlaceHistoryMapper} instance
* @param historian a {@link Historian} instance
*/
@@ -95,12 +109,19 @@
this.historian = historian;
}
- // TODO - document
+ /**
+ * Handle the current history token. Typically called at application start, to
+ * ensure bookmark launches work.
+ */
public void handleCurrentHistory() {
handleHistoryToken(historian.getToken());
}
- // TODO - document
+ /**
+ * Initialize this place history handler.
+ *
+ * @return a registration object to de-register the handler
+ */
public HandlerRegistration register(PlaceController placeController,
EventBus eventBus, Place defaultPlace) {
this.placeController = placeController;