blob: 3d2fffd5c80b9c1fec2baa9be9c3a0a9e3e543f8 [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.cell.client.Cell;
import com.google.gwt.cell.client.IconCellDecorator;
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.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.sample.expenses.client.style.Styles;
import com.google.gwt.sample.expenses.shared.EmployeeProxy;
import com.google.gwt.sample.expenses.shared.ExpensesRequestFactory;
import com.google.gwt.user.cellview.client.CellTree;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.Range;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.gwt.view.client.TreeViewModel;
import com.google.web.bindery.requestfactory.gwt.ui.client.EntityProxyKeyProvider;
import com.google.web.bindery.requestfactory.shared.EntityProxyId;
import com.google.web.bindery.requestfactory.shared.Receiver;
import java.util.List;
/**
* The employee tree located on the left of the app.
*/
public class ExpenseTree extends Composite {
/**
* Custom listener for this widget.
*/
public interface Listener {
/**
* Called when the user selects a tree item.
*
* @param department the selected department name
* @param employee the selected employee
*/
void onSelection(String department, EntityProxyId<EmployeeProxy> employeeId);
}
interface Template extends SafeHtmlTemplates {
@Template("<span class=\"{0}\">{1}</span>")
SafeHtml span(String classes, String userName);
}
/**
* A {@link AbstractCell} that represents an {@link EmployeeProxy}.
*/
private class EmployeeCell extends IconCellDecorator<EmployeeProxy> {
public EmployeeCell() {
super(Styles.resources().userIcon(), new AbstractCell<EmployeeProxy>() {
private final String usernameStyle = Styles.common().usernameTreeItem();
private final String usernameStyleSelected = Styles.common().usernameTreeItemSelected();
@Override
public boolean dependsOnSelection() {
return true;
}
@Override
public void render(Context context, EmployeeProxy value,
SafeHtmlBuilder sb) {
if (value != null) {
StringBuilder classesBuilder = new StringBuilder(usernameStyle);
if (lastEmployee != null
&& lastEmployee.getId().equals(value.getId())) {
classesBuilder.append(" ").append(usernameStyleSelected);
}
sb.appendEscaped(value.getDisplayName());
sb.appendHtmlConstant("<br>");
sb.append(template.span(classesBuilder.toString(),
value.getUserName()));
}
}
});
if (template == null) {
template = GWT.create(Template.class);
}
}
}
/**
* The {@link ListDataProvider} used for Employee lists.
*/
private class EmployeeListDataProvider extends
AsyncDataProvider<EmployeeProxy> {
private final String department;
public EmployeeListDataProvider(String department) {
super(null);
this.department = department;
}
@Override
public void addDataDisplay(HasData<EmployeeProxy> display) {
super.addDataDisplay(display);
// Request the count anytime a view is added.
requestFactory.employeeRequest().countEmployeesByDepartment(department).fire(
new Receiver<Long>() {
@Override
public void onSuccess(Long response) {
updateRowCount(response.intValue(), true);
}
});
}
@Override
protected void onRangeChanged(HasData<EmployeeProxy> view) {
Range range = view.getVisibleRange();
requestFactory.employeeRequest().findEmployeeEntriesByDepartment(
department, range.getStart(), range.getLength()).with(
getEmployeeMenuProperties()).fire(
new Receiver<List<EmployeeProxy>>() {
@Override
public void onSuccess(List<EmployeeProxy> response) {
updateRowData(0, response);
}
});
}
}
/**
* The {@link TreeViewModel} used to browse expense reports.
*/
private class ExpensesTreeViewModel implements TreeViewModel {
/**
* The department cell singleton.
*/
private final Cell<String> departmentCell = new TextCell();
/**
* The {@link EmployeeCell} singleton.
*/
private final EmployeeCell employeeCell = new EmployeeCell();
public <T> NodeInfo<?> getNodeInfo(T value) {
if (value == null) {
// Top level.
return new DefaultNodeInfo<String>(departments, departmentCell,
selectionModel, null);
} else if (isAllDepartment(value)) {
// Employees are not displayed under the 'All' Department.
return null;
} else if (value instanceof String) {
// Second level.
EmployeeListDataProvider dataProvider = new EmployeeListDataProvider(
(String) value);
return new DefaultNodeInfo<EmployeeProxy>(dataProvider, employeeCell,
selectionModel, null);
}
return null;
}
/**
* @return true if the object is the All department
*/
public boolean isAllDepartment(Object value) {
return departments.getList().get(0).equals(value);
}
/**
* @return true if the object is a department
*/
public boolean isDepartment(Object value) {
List<String> list = departments.getList();
String string = value.toString();
return list.contains(string);
}
public boolean isLeaf(Object value) {
return value != null && (!isDepartment(value) || isAllDepartment(value));
}
}
private static Template template;
/**
* The data provider that provides departments.
*/
private final ListDataProvider<String> departments = new ListDataProvider<String>();
/**
* The last selected department.
*/
private String lastDepartment;
/**
* The last selected employee.
*/
private EmployeeProxy lastEmployee;
/**
* The listener of this widget.
*/
private Listener listener;
/**
* The factory used to send requests.
*/
private final ExpensesRequestFactory requestFactory;
/**
* The shared {@link SingleSelectionModel}.
*/
private final SingleSelectionModel<Object> selectionModel = new SingleSelectionModel<Object>(
new ProvidesKey<Object>() {
EntityProxyKeyProvider<EmployeeProxy> keyProvider = new EntityProxyKeyProvider<EmployeeProxy>();
public Object getKey(Object item) {
if (item instanceof EmployeeProxy) {
return keyProvider.getKey((EmployeeProxy) item);
}
return item;
}
});
/**
* The main widget.
*/
private CellTree tree;
public ExpenseTree(ExpensesRequestFactory requestFactory) {
this.requestFactory = requestFactory;
// Initialize the departments.
List<String> departmentList = departments.getList();
departmentList.add("All");
for (String department : ExpensesApp.DEPARTMENTS) {
departmentList.add(department);
}
// Initialize the widget.
createTree();
initWidget(tree);
getElement().getStyle().setOverflow(Overflow.AUTO);
}
public void setListener(Listener listener) {
this.listener = listener;
}
/**
* Create the {@link CellTree}.
*/
private void createTree() {
final ExpensesTreeViewModel model = new ExpensesTreeViewModel();
// Listen for selection. We need to add this handler before the CellBrowser
// adds its own handler.
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
public void onSelectionChange(SelectionChangeEvent event) {
Object selected = selectionModel.getSelectedObject();
if (selected == null) {
lastEmployee = null;
lastDepartment = "";
} else if (selected instanceof EmployeeProxy) {
lastEmployee = (EmployeeProxy) selected;
lastDepartment = lastEmployee.getDepartment();
} else if (selected instanceof String) {
lastEmployee = null;
if (model.isAllDepartment(selected)) {
lastDepartment = "";
} else {
lastDepartment = (String) selected;
}
}
if (listener != null) {
listener.onSelection(lastDepartment, lastEmployee == null ? null
: lastEmployee.stableId());
}
}
});
// Create a CellBrowser.
tree = new CellTree(model, null);
tree.setAnimationEnabled(true);
}
private String[] getEmployeeMenuProperties() {
return new String[] {"displayName", "userName"};
}
}