/* * 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.dynatablerf.client.widgets; import static com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory.SchoolCalendarRequest.ALL_DAYS; import com.google.gwt.cell.client.TextCell; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.shared.EventBus; import com.google.gwt.resources.client.CssResource; import com.google.gwt.sample.dynatablerf.client.events.EditPersonEvent; import com.google.gwt.sample.dynatablerf.client.events.FilterChangeEvent; import com.google.gwt.sample.dynatablerf.shared.AddressProxy; import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory; import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory.PersonRequest; import com.google.gwt.sample.dynatablerf.shared.PersonProxy; import com.google.gwt.sample.dynatablerf.shared.ScheduleProxy; import com.google.gwt.sample.dynatablerf.shared.TimeSlotProxy; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.cellview.client.DataGrid; import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy; import com.google.gwt.user.cellview.client.SimplePager; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.DockLayoutPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.view.client.Range; import com.google.gwt.view.client.RangeChangeEvent; import com.google.gwt.view.client.SelectionChangeEvent; import com.google.gwt.view.client.SingleSelectionModel; import com.google.web.bindery.requestfactory.shared.EntityProxyChange; import com.google.web.bindery.requestfactory.shared.EntityProxyId; import com.google.web.bindery.requestfactory.shared.Receiver; import com.google.web.bindery.requestfactory.shared.WriteOperation; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * A paging table with summaries of all known people. */ public class SummaryWidget extends Composite { interface Binder extends UiBinder<Widget, SummaryWidget> { } interface Style extends CssResource { } interface TableResources extends DataGrid.Resources { @Override @Source(value = {DataGrid.Style.DEFAULT_CSS, "DataGridPatch.css"}) DataGrid.Style dataGridStyle(); } private class DescriptionColumn extends Column<PersonProxy, String> { public DescriptionColumn() { super(new TextCell()); } @Override public String getValue(PersonProxy object) { return object.getDescription(); } } private class NameColumn extends Column<PersonProxy, String> { public NameColumn() { super(new TextCell()); } @Override public String getValue(PersonProxy object) { return object.getName(); } } private class ScheduleColumn extends Column<PersonProxy, String> { public ScheduleColumn() { super(new TextCell()); } @Override public String getValue(PersonProxy object) { return object.getScheduleDescription(); } } @UiField DockLayoutPanel dock; @UiField(provided = true) SimplePager pager = new SimplePager(); @UiField(provided = true) DataGrid<PersonProxy> table; private final EventBus eventBus; private List<Boolean> filter = new ArrayList<Boolean>(ALL_DAYS); private int lastFetch; private final int numRows; private boolean pending; private final DynaTableRequestFactory requestFactory; private final SingleSelectionModel<PersonProxy> selectionModel = new SingleSelectionModel<PersonProxy>(); public SummaryWidget(EventBus eventBus, DynaTableRequestFactory requestFactory, int numRows) { this.eventBus = eventBus; this.requestFactory = requestFactory; this.numRows = numRows; table = new DataGrid<PersonProxy>(numRows, GWT.<TableResources> create(TableResources.class)); initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this)); Column<PersonProxy, String> nameColumn = new NameColumn(); table.addColumn(nameColumn, "Name"); table.setColumnWidth(nameColumn, "25ex"); Column<PersonProxy, String> descriptionColumn = new DescriptionColumn(); table.addColumn(descriptionColumn, "Description"); table.setColumnWidth(descriptionColumn, "40ex"); table.addColumn(new ScheduleColumn(), "Schedule"); table.setRowCount(numRows, false); table.setSelectionModel(selectionModel); table.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.DISABLED); EntityProxyChange.registerForProxyType(eventBus, PersonProxy.class, new EntityProxyChange.Handler<PersonProxy>() { @Override public void onProxyChange(EntityProxyChange<PersonProxy> event) { SummaryWidget.this.onPersonChanged(event); } }); FilterChangeEvent.register(eventBus, new FilterChangeEvent.Handler() { @Override public void onFilterChanged(FilterChangeEvent e) { filter.set(e.getDay(), e.isSelected()); if (!pending) { pending = true; Scheduler.get().scheduleFinally(new ScheduledCommand() { @Override public void execute() { pending = false; fetch(0); } }); } } }); selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { @Override public void onSelectionChange(SelectionChangeEvent event) { SummaryWidget.this.refreshSelection(); } }); fetch(0); } @UiHandler("create") void onCreate(ClickEvent event) { PersonRequest context = requestFactory.personRequest(); AddressProxy address = context.create(AddressProxy.class); ScheduleProxy schedule = context.create(ScheduleProxy.class); schedule.setTimeSlots(new ArrayList<TimeSlotProxy>()); PersonProxy person = context.edit(context.create(PersonProxy.class)); person.setAddress(address); person.setClassSchedule(schedule); context.persist().using(person); eventBus.fireEvent(new EditPersonEvent(person, context)); } void onPersonChanged(EntityProxyChange<PersonProxy> event) { if (WriteOperation.PERSIST.equals(event.getWriteOperation())) { // Re-fetch if we're already displaying the last page if (table.isRowCountExact()) { fetch(lastFetch + 1); } } if (WriteOperation.UPDATE.equals(event.getWriteOperation())) { EntityProxyId<PersonProxy> personId = event.getProxyId(); // Is the changing record onscreen? int displayOffset = offsetOf(personId); if (displayOffset != -1) { // Record is onscreen and may differ from our data requestFactory.find(personId).fire(new Receiver<PersonProxy>() { @Override public void onSuccess(PersonProxy person) { // Re-check offset in case of changes while waiting for data int offset = offsetOf(person.stableId()); if (offset != -1) { table.setRowData(table.getPageStart() + offset, Collections.singletonList(person)); } } }); } } } @UiHandler("table") void onRangeChange(RangeChangeEvent event) { Range r = event.getNewRange(); int start = r.getStart(); fetch(start); } void refreshSelection() { PersonProxy person = selectionModel.getSelectedObject(); if (person == null) { return; } eventBus.fireEvent(new EditPersonEvent(person)); selectionModel.setSelected(person, false); } private void fetch(final int start) { lastFetch = start; requestFactory.schoolCalendarRequest().getPeople(start, numRows, filter).fire( new Receiver<List<PersonProxy>>() { @Override public void onSuccess(List<PersonProxy> response) { if (lastFetch != start) { return; } int responses = response.size(); table.setRowData(start, response); pager.setPageStart(start); if (start == 0 || !table.isRowCountExact()) { table.setRowCount(start + responses, responses < numRows); } } }); } private int offsetOf(EntityProxyId<PersonProxy> personId) { List<PersonProxy> displayedItems = table.getVisibleItems(); for (int offset = 0, j = displayedItems.size(); offset < j; offset++) { if (personId.equals(displayedItems.get(offset).stableId())) { return offset; } } return -1; } }