blob: 4b83c8e23a29f1c7070955291cce22113fa7ff92 [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.gwt.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.requestfactory.shared.Receiver;
import com.google.gwt.sample.bikeshed.style.client.Styles;
import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
import com.google.gwt.user.cellview.client.CellTree;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.valuestore.shared.Property;
import com.google.gwt.valuestore.shared.SyncResult;
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 java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* 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, EmployeeRecord employee);
}
/**
* A {@link AbstractCell} that represents an {@link EmployeeRecord}.
*/
private class EmployeeCell extends IconCellDecorator<EmployeeRecord> {
public EmployeeCell() {
super(Styles.resources().userIcon(), new AbstractCell<EmployeeRecord>() {
private final String usernameStyle = Styles.common().usernameTreeItem();
private final String usernameStyleSelected =
Styles.common().usernameTreeItemSelected();
@Override
public boolean dependsOnSelection() {
return true;
}
@Override
public void render(
EmployeeRecord value, Object viewData, StringBuilder sb) {
if (value != null) {
sb.append(value.getDisplayName()).append("<br>");
sb.append("<span class='").append(usernameStyle);
if (lastEmployee != null
&& lastEmployee.getId().equals(value.getId())) {
sb.append(" ").append(usernameStyleSelected);
}
sb.append("'>");
sb.append(value.getUserName());
sb.append("</span>");
}
}
});
}
}
/**
* The {@link ListDataProvider} used for Employee lists.
*/
private class EmployeeListDataProvider extends AsyncDataProvider<
EmployeeRecord> implements Receiver<List<EmployeeRecord>> {
private final String department;
public EmployeeListDataProvider(String department) {
this.department = department;
}
@Override
public void addDataDisplay(HasData<EmployeeRecord> display) {
super.addDataDisplay(display);
// Request the count anytime a view is added.
requestFactory.employeeRequest().countEmployeesByDepartment(
department).fire(new Receiver<Long>() {
public void onSuccess(Long response, Set<SyncResult> syncResults) {
updateRowCount(response.intValue(), true);
}
});
}
public void onSuccess(
List<EmployeeRecord> response, Set<SyncResult> syncResults) {
updateRowData(0, response);
}
@Override
protected void onRangeChanged(HasData<EmployeeRecord> view) {
Range range = view.getVisibleRange();
requestFactory.employeeRequest().findEmployeeEntriesByDepartment(
department, range.getStart(), range.getLength()).forProperties(
getEmployeeMenuProperties()).fire(this);
}
}
/**
* 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<EmployeeRecord>(
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) {
return departments.getList().contains(value.toString());
}
public boolean isLeaf(Object value) {
return !isDepartment(value) || isAllDepartment(value);
}
}
/**
* The data provider that provides departments.
*/
private ListDataProvider<String> departments = new ListDataProvider<String>();
/**
* The last selected department.
*/
private String lastDepartment;
/**
* The last selected employee.
*/
private EmployeeRecord lastEmployee;
/**
* The listener of this widget.
*/
private Listener listener;
/**
* The factory used to send requests.
*/
private ExpensesRequestFactory requestFactory;
/**
* The shared {@link SingleSelectionModel}.
*/
private final SingleSelectionModel<Object> selectionModel =
new SingleSelectionModel<Object>();
/**
* The main widget.
*/
private CellTree tree;
public ExpenseTree() {
// Initialize the departments.
List<String> departmentList = departments.getList();
departmentList.add("All");
for (String department : Expenses.DEPARTMENTS) {
departmentList.add(department);
}
// Initialize the widget.
createTree();
initWidget(tree);
getElement().getStyle().setOverflow(Overflow.AUTO);
}
public void setListener(Listener listener) {
this.listener = listener;
}
public void setRequestFactory(ExpensesRequestFactory factory) {
this.requestFactory = factory;
}
/**
* 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 = null;
} else if (selected instanceof EmployeeRecord) {
lastEmployee = (EmployeeRecord) selected;
} else if (selected instanceof String) {
lastEmployee = null;
if (model.isAllDepartment(selected)) {
lastDepartment = null;
} else {
lastDepartment = (String) selected;
}
}
if (listener != null) {
listener.onSelection(lastDepartment, lastEmployee);
}
}
});
selectionModel.setKeyProvider(new ProvidesKey<Object>() {
public Object getKey(Object item) {
if (item instanceof EmployeeRecord) {
return Expenses.EMPLOYEE_RECORD_KEY_PROVIDER.getKey(
(EmployeeRecord) item);
}
return item;
}
});
// Create a CellBrowser.
CellTree.Resources resources = GWT.create(CellTree.CleanResources.class);
tree = new CellTree(model, null, resources);
tree.setAnimationEnabled(true);
}
private Collection<Property<?>> getEmployeeMenuProperties() {
List<Property<?>> columns = new ArrayList<Property<?>>();
columns.add(EmployeeRecord.displayName);
columns.add(EmployeeRecord.userName);
return columns;
}
}