| /* |
| * 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; |
| } |
| } |