blob: 1d098f718770486464fec4f78e214225862dcc22 [file] [log] [blame]
/*
* Copyright 2011 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 com.google.gwt.cell.client.ClickableTextCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.editor.client.EditorDelegate;
import com.google.gwt.editor.client.ValueAwareEditor;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.sample.dynatablerf.client.widgets.SummaryWidget.TableResources;
import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory.ScheduleRequest;
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.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
/**
* Edits a list of time slots.
*/
public class TimeSlotListWidget extends Composite implements ValueAwareEditor<List<TimeSlotProxy>> {
interface TimeSlotListWidgetUiBinder extends UiBinder<Widget, TimeSlotListWidget> {
}
private class ScheduleRow {
int hour;
ScheduleRow(int hour) {
this.hour = hour;
}
public int getHour() {
return hour;
}
public boolean isInUse(WeekDay day) {
return currentSchedule.contains(new TimeSlotKey(day, hour));
}
public void toggleInUse(WeekDay day) {
final TimeSlotKey key = new TimeSlotKey(day, hour);
if (currentSchedule.contains(key)) {
currentSchedule.remove(key);
table.redraw();
} else if (!existingSlots.containsKey(key)) {
acceptClicks = false;
ScheduleRequest context = factory.scheduleRequest();
context.createTimeSlot(day.ordinal(), hour * 60, hour * 60 + 50).fire(
new Receiver<TimeSlotProxy>() {
public void onSuccess(TimeSlotProxy slot) {
existingSlots.put(key, slot);
backing.add(slot);
currentSchedule.add(key);
table.redraw();
acceptClicks = true;
}
});
} else {
currentSchedule.add(key);
table.redraw();
}
}
}
private static class TimeSlotKey {
private int hour;
private WeekDay day;
TimeSlotKey(WeekDay day, int hour) {
this.day = day;
this.hour = hour;
}
TimeSlotKey(TimeSlotProxy slot) {
day = WeekDay.fromInt(slot.getDayOfWeek());
hour = slot.getStartMinutes() / 60;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
TimeSlotKey other = (TimeSlotKey) obj;
if (day == null) {
if (other.day != null) {
return false;
}
} else if (!day.equals(other.day)) {
return false;
}
if (hour != other.hour) {
return false;
}
return true;
}
@Override
public int hashCode() {
return 31 * (31 + ((day == null) ? 0 : day.hashCode())) + hour;
}
}
private class WeekDayColumn extends Column<ScheduleRow, String> {
private WeekDay day;
public WeekDayColumn(WeekDay day) {
super(new ClickableTextCell());
this.day = day;
}
@Override
public String getValue(ScheduleRow row) {
if (day == null) {
int hour = row.getHour();
return Integer.toString(hour <= 12 ? hour : hour - 12) + ":00"
+ ((hour < 12) ? "AM" : "PM");
}
return row.isInUse(day) ? "X" : ".";
}
}
private static final int ROWS_IN_A_DAY = 9;
private static final int FIRST_HOUR = 8;
private static TimeSlotListWidgetUiBinder uiBinder = GWT.create(
TimeSlotListWidgetUiBinder.class);
@UiField(provided = true)
CellTable<ScheduleRow> table;
private enum WeekDay {
SUNDAY("Su"), MONDAY("Mo"), TUESDAY("Tu"), WEDNESDAY("We"),
THURSDAY("Th"), FRIDAY("Fr"), SATURDAY("Sa");
public static WeekDay fromInt(int ordinal) {
return values()[ordinal];
}
private String shortName;
WeekDay(String shortName) {
this.shortName = shortName;
}
public String getShortName() {
return shortName;
}
}
private List<TimeSlotProxy> backing;
private HashSet<TimeSlotKey> currentSchedule;
private HashMap<TimeSlotKey, TimeSlotProxy> existingSlots;
private DynaTableRequestFactory factory;
private HashSet<TimeSlotKey> initialSchedule;
private boolean acceptClicks = true;
public TimeSlotListWidget(DynaTableRequestFactory factory) {
this.factory = factory;
table = new CellTable<TimeSlotListWidget.ScheduleRow>(ROWS_IN_A_DAY,
GWT.<TableResources> create(TableResources.class));
table.addColumn(new WeekDayColumn(null), "Hour");
for (WeekDay day : WeekDay.values()) {
WeekDayColumn col = new WeekDayColumn(day);
class Updater implements FieldUpdater<ScheduleRow, String> {
private WeekDay columnDay;
public Updater(WeekDay day) {
columnDay = day;
}
public void update(int index, ScheduleRow row, String value) {
if (acceptClicks) {
row.toggleInUse(columnDay);
}
}
}
FieldUpdater<ScheduleRow, String> fieldUpdater = new Updater(day);
col.setFieldUpdater(fieldUpdater);
table.addColumn(col, day.getShortName());
}
table.setRowCount(ROWS_IN_A_DAY, false);
table.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.DISABLED);
initWidget(uiBinder.createAndBindUi(this));
}
public void flush() {
HashMap<TimeSlotProxy, TimeSlotKey> index = new HashMap<TimeSlotProxy, TimeSlotKey>();
for (TimeSlotProxy slot : backing) {
index.put(slot, new TimeSlotKey(slot));
}
// Compute slots that need to be removed from the backing
initialSchedule.removeAll(currentSchedule);
for (Iterator<TimeSlotProxy> iterator = backing.iterator(); iterator.hasNext();) {
TimeSlotProxy slot = iterator.next();
TimeSlotKey key = index.get(slot);
if (initialSchedule.contains(key)) {
iterator.remove();
}
}
}
public void onPropertyChange(String... paths) {
}
public void setDelegate(EditorDelegate<List<TimeSlotProxy>> delegate) {
}
public void setValue(List<TimeSlotProxy> value) {
backing = value;
currentSchedule = new HashSet<TimeSlotKey>();
existingSlots = new HashMap<TimeSlotKey, TimeSlotProxy>();
initialSchedule = new HashSet<TimeSlotKey>();
for (TimeSlotProxy slot : backing) {
TimeSlotKey key = new TimeSlotKey(slot);
currentSchedule.add(key);
existingSlots.put(key, slot);
initialSchedule.add(new TimeSlotKey(slot));
}
ArrayList<ScheduleRow> rows = new ArrayList<ScheduleRow>(ROWS_IN_A_DAY);
for (int i = 0; i < ROWS_IN_A_DAY; i++) {
rows.add(new ScheduleRow(FIRST_HOUR + i));
}
table.setRowData(rows);
}
}