blob: 1b4f8f5df1be94c3e34f543476cb850cc1c69733 [file] [log] [blame]
/*
* 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.cell.client.AbstractCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.sample.expenses.client.request.ExpenseProxy;
import com.google.gwt.sample.expenses.client.request.ExpensesRequestFactory;
import com.google.gwt.sample.expenses.client.request.ReportProxy;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Composite;
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.SelectionChangeEvent;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* TODO: doc.
*/
public class MobileExpenseList extends Composite implements MobilePage {
/**
* TODO: doc.
*/
public interface Listener {
void onCreateExpense(ReportProxy report);
void onEditReport(ReportProxy report);
void onExpenseSelected(ExpenseProxy expense);
}
interface Template extends SafeHtmlTemplates {
@Template("<div class=\"item\">{0}{1} ({2})</div>")
SafeHtml div(SafeHtml approvalIcon, String description, String amount);
}
/**
* The cell used to render {@link ExpenseProxy}s.
*/
private class ExpenseCell extends AbstractCell<ExpenseProxy> {
private final SafeHtml approvedHtml;
private final String approvedText = Expenses.Approval.APPROVED.getText();
private final SafeHtml blankHtml;
private final SafeHtml deniedHtml;
private final String deniedText = Expenses.Approval.DENIED.getText();
public ExpenseCell() {
if (template == null) {
template = GWT.create(Template.class);
}
approvedHtml = Expenses.Approval.APPROVED.getIconHtml();
blankHtml = Expenses.Approval.BLANK.getIconHtml();
deniedHtml = Expenses.Approval.DENIED.getIconHtml();
}
@Override
public void render(ExpenseProxy value, Object viewData, SafeHtmlBuilder sb) {
String approval = value.getApproval();
SafeHtml approvalIcon;
if (approvedText.equals(approval)) {
approvalIcon = approvedHtml;
} else if (deniedText.equals(approval)) {
approvalIcon = deniedHtml;
} else {
approvalIcon = blankHtml;
}
sb.append(template.div(approvalIcon, value.getDescription(),
ExpensesMobile.formatCurrency(value.getAmount())));
}
}
private static Template template;
/**
* The auto refresh interval in milliseconds.
*/
private static final int REFRESH_INTERVAL = 5000;
private final ExpensesRequestFactory requestFactory;
private final CellList<ExpenseProxy> expenseList;
private final AsyncDataProvider<ExpenseProxy> expenseDataProvider;
private final NoSelectionModel<ExpenseProxy> expenseSelection;
/**
* The set of Expense keys that we already know are denied. When a new key is
* added, we compare it to the list of known keys to determine if it is new.
*/
private Set<Object> knownDeniedKeys = null;
/**
* The receiver for the last request.
*/
private Receiver<List<ExpenseProxy>> lastReceiver;
private ReportProxy report;
private final Listener listener;
/**
* The {@link Timer} used to periodically refresh the table.
*/
private final Timer refreshTimer = new Timer() {
@Override
public void run() {
requestExpenses();
}
};
public MobileExpenseList(
final Listener listener, final ExpensesRequestFactory requestFactory) {
this.listener = listener;
this.requestFactory = requestFactory;
expenseDataProvider = new AsyncDataProvider<ExpenseProxy>(Expenses.EXPENSE_RECORD_KEY_PROVIDER) {
@Override
protected void onRangeChanged(HasData<ExpenseProxy> view) {
requestExpenses();
}
};
expenseList = new CellList<ExpenseProxy>(new ExpenseCell());
expenseList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.DISABLED);
expenseSelection = new NoSelectionModel<ExpenseProxy>();
expenseList.setSelectionModel(expenseSelection);
expenseSelection.addSelectionChangeHandler(
new SelectionChangeEvent.Handler() {
public void onSelectionChange(SelectionChangeEvent event) {
listener.onExpenseSelected(
expenseSelection.getLastSelectedObject());
}
});
expenseDataProvider.addDataDisplay(expenseList);
initWidget(expenseList);
}
@Override
public Widget asWidget() {
return this;
}
public String getPageTitle() {
return report != null ? report.getPurpose() : "";
}
public boolean needsAddButton() {
return true;
}
public String needsCustomButton() {
return "Edit";
}
public boolean needsRefreshButton() {
return true;
}
public void onAdd() {
listener.onCreateExpense(report);
}
public void onCustom() {
listener.onEditReport(report);
}
public void onRefresh(boolean clear) {
if (clear) {
expenseDataProvider.updateRowCount(0, true);
}
requestExpenses();
}
public void show(ReportProxy report) {
this.report = report;
knownDeniedKeys = null;
onRefresh(true);
}
private String[] getExpenseColumns() {
return new String[]{"description", "amount"};
}
/**
* Request the expenses.
*/
private void requestExpenses() {
refreshTimer.cancel();
if (requestFactory == null || report == null) {
return;
}
lastReceiver = new Receiver<List<ExpenseProxy>>() {
@Override
public void onSuccess(List<ExpenseProxy> newValues) {
if (this == lastReceiver) {
int size = newValues.size();
expenseDataProvider.updateRowCount(size, true);
expenseDataProvider.updateRowData(0, newValues);
// Add the new keys to the known keys.
boolean isInitialData = knownDeniedKeys == null;
if (knownDeniedKeys == null) {
knownDeniedKeys = new HashSet<Object>();
}
for (ExpenseProxy value : newValues) {
Object key = expenseDataProvider.getKey(value);
String approval = value.getApproval();
if (Expenses.Approval.DENIED.getText().equals(approval)) {
if (!isInitialData && !knownDeniedKeys.contains(key)) {
(new PhaseAnimation.CellListPhaseAnimation<ExpenseProxy>(
expenseList, value, expenseDataProvider)).run();
}
knownDeniedKeys.add(key);
} else {
knownDeniedKeys.remove(key);
}
}
refreshTimer.schedule(REFRESH_INTERVAL);
}
}
};
requestFactory.expenseRequest().findExpensesByReport(
report.getId()).with(getExpenseColumns()).fire(
lastReceiver);
}
}