Java tutorial
/* * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. * * The Apereo Foundation licenses this file to you 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 org.unitime.timetable.gwt.client.rooms; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.unitime.timetable.gwt.client.page.UniTimeNotifications; import org.unitime.timetable.gwt.client.widgets.P; import org.unitime.timetable.gwt.client.widgets.UniTimeConfirmationDialog; import org.unitime.timetable.gwt.command.client.GwtRpcService; import org.unitime.timetable.gwt.command.client.GwtRpcServiceAsync; import org.unitime.timetable.gwt.resources.GwtConstants; import org.unitime.timetable.gwt.resources.GwtMessages; import org.unitime.timetable.gwt.shared.RoomInterface; import org.unitime.timetable.gwt.shared.RoomInterface.PeriodInterface; import org.unitime.timetable.gwt.shared.RoomInterface.PeriodPreferenceModel; import org.unitime.timetable.gwt.shared.RoomInterface.PreferenceInterface; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.AbsolutePanel; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HasValue; import com.google.gwt.user.client.ui.Hidden; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.datepicker.client.CalendarUtil; /** * @author Tomas Muller */ public class PeriodPreferencesWidget extends Composite implements HasValue<PeriodPreferenceModel> { private static GwtRpcServiceAsync RPC = GWT.create(GwtRpcService.class); private static final GwtConstants CONSTANTS = GWT.create(GwtConstants.class); private static final GwtMessages MESSAGES = GWT.create(GwtMessages.class); private AbsolutePanel iPanel; private PreferenceInterface iPreference = null; private P iSelectedIcon = null, iSelectedTitle = null; private PeriodPreferenceModel iModel; protected boolean iEditable = true; private CheckBox iHorizontal; private List<Cell> iCells = new ArrayList<Cell>(); public PeriodPreferencesWidget(boolean editable) { iEditable = editable; iPanel = new AbsolutePanel(); iHorizontal = new CheckBox(MESSAGES.periodPreferenceHorizontal()); iHorizontal.addValueChangeHandler(new ValueChangeHandler<Boolean>() { @Override public void onValueChange(ValueChangeEvent<Boolean> event) { RoomCookie.getInstance().setHorizontal(iHorizontal.getValue()); render(); } }); initWidget(iPanel); } public AbsolutePanel getPanel() { return iPanel; } public boolean isEditable() { return iEditable && iModel != null; } public void setEditable(boolean editable) { iEditable = editable; } public boolean isEditable(PreferenceInterface preference) { return isEditable() && preference.isEditable(); } public boolean isEditable(int day, int slot) { return isEditable() && iModel.getPeriod(day, slot) != null; } public PeriodPreferenceModel getModel() { return iModel; } public boolean isHorizontal() { return iHorizontal.getValue(); } public void setHorizontal(boolean horizontal) { iHorizontal.setValue(horizontal); RoomCookie.getInstance().setHorizontal(horizontal); render(); } public void setModel(PeriodPreferenceModel model) { iModel = model; if (RoomCookie.getInstance().hasOrientation()) iHorizontal.setValue(RoomCookie.getInstance().areRoomsHorizontal()); else iHorizontal.setValue(model.isDefaultHorizontal()); iPreference = iModel.getSelectedPreference(); if (iPreference == null) iPreference = iModel.getPreferences().get(0); render(); } public void insert(final RootPanel panel, Long eventAvailability) { String[] ids = panel.getElement().getInnerHTML().trim().split(":"); Long locationId = Long.valueOf(ids[0]); Long examTypeId = Long.valueOf(ids[1]); RPC.execute(RoomInterface.PeriodPreferenceRequest.load(locationId, examTypeId), new AsyncCallback<PeriodPreferenceModel>() { @Override public void onFailure(Throwable caught) { UniTimeNotifications.error(MESSAGES.failedToLoadPeriodPreferences(caught.getMessage())); } @Override public void onSuccess(PeriodPreferenceModel result) { panel.getElement().setInnerText(null); setModel(result); panel.add(PeriodPreferencesWidget.this); panel.setVisible(true); } }); } public static String slot2short(int slot) { int h = slot / 12; int m = 5 * (slot % 12); if (CONSTANTS.useAmPm()) return (h > 12 ? h - 12 : h) + ":" + (m < 10 ? "0" : "") + m + (h == 24 ? "a" : h >= 12 ? "p" : "a"); else return h + ":" + (m < 10 ? "0" : "") + m; } private class Cell extends P { private int iDay, iSlot; private Date iDate; private PeriodInterface iPeriod; Cell(int day, int slot, Date date, PeriodInterface period) { super("cell", "item", isEditable() && period != null ? "clickable" : null, period == null ? "disabled" : null, period != null && iModel.isAssigned(period) ? "highlight" : null); iDay = day; iSlot = slot; iDate = date; iPeriod = period; if (period != null) { PreferenceInterface preference = iModel.getPreference(day, slot); if (preference == null) { getElement().getStyle().clearBackgroundColor(); setHTML(""); setTitle(""); } else { getElement().getStyle().setBackgroundColor(preference.getColor()); setTitle(DateTimeFormat.getFormat(CONSTANTS.examPeriodDateFormat()).format(date) + " " + slot2short(slot) + (period == null ? "" : " - " + slot2short(slot + period.getLength())) + ": " + preference.getName()); } if (isEditable()) addMouseDownHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { setOption(iPreference); } }); } } public PeriodInterface getPeriod() { return iPeriod; } public void setOption(PreferenceInterface preference) { setOption(preference, true); } public void setOption(PreferenceInterface preference, boolean fireChangeEvent) { if (!isEditable() || iPeriod == null) return; if (preference != null && fireChangeEvent) { if (preference.getCode().equals("R")) { if (iModel.hasPreference()) { PreferenceInterface p = iModel.getPreference("0"); for (Cell cell : iCells) { if (cell.getPeriod() != null) { PreferenceInterface pref = iModel.getPreference(cell.getPeriod().getDay(), cell.getPeriod().getStartSlot()); if (pref != null) cell.setOption(p, false); } } } } else if (!preference.getCode().equals("0")) { if (iModel.hasRequired()) { PreferenceInterface p = iModel.getDefaultPreference(); for (Cell cell : iCells) { if (cell.getPeriod() != null) { PreferenceInterface pref = iModel.getPreference(cell.getPeriod().getDay(), cell.getPeriod().getStartSlot()); if (pref != null) cell.setOption(p, false); } } } } } iModel.setPreference(iDay, iSlot, preference); if (preference == null) { getElement().getStyle().clearBackgroundColor(); setHTML(""); setTitle(""); } else { getElement().getStyle().setBackgroundColor(preference.getColor()); setTitle(DateTimeFormat.getFormat(CONSTANTS.examPeriodDateFormat()).format(iDate) + " " + slot2short(iSlot) + " - " + slot2short(iSlot + iPeriod.getLength()) + ": " + preference.getName()); } if (fireChangeEvent) ValueChangeEvent.fire(PeriodPreferencesWidget.this, getValue()); } } private class D extends P { private int iDay, iSlot; private Date iDate; private PeriodInterface iPeriod; private D(int day, int slot, Date date, PeriodInterface period) { super("cell", "day", isEditable() && period != null ? "clickable" : null, period == null ? "unavailable" : null); iDay = day; iSlot = slot; iDate = date; iPeriod = period; setText(DateTimeFormat.getFormat("d").format(date)); if (period != null) { PreferenceInterface preference = iModel.getPreference(day, slot); if (preference == null) { getElement().getStyle().clearBackgroundColor(); setTitle(""); } else { getElement().getStyle().setBackgroundColor(preference.getColor()); setTitle(DateTimeFormat.getFormat(CONSTANTS.examPeriodDateFormat()).format(date) + " " + slot2short(slot) + (period == null ? "" : " - " + slot2short(slot + period.getLength())) + ": " + preference.getName()); } if (isEditable()) addMouseDownHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { setOption(iPreference); } }); } } public void setOption(PreferenceInterface preference) { if (!isEditable() || iPeriod == null) return; iModel.setPreference(iDay, iSlot, preference); if (preference == null) { getElement().getStyle().clearBackgroundColor(); setTitle(""); } else { getElement().getStyle().setBackgroundColor(preference.getColor()); setTitle(DateTimeFormat.getFormat(CONSTANTS.examPeriodDateFormat()).format(iDate) + " " + slot2short(iSlot) + " - " + slot2short(iSlot + iPeriod.getLength()) + ": " + preference.getName()); } ValueChangeEvent.fire(PeriodPreferencesWidget.this, getValue()); } } @SuppressWarnings("deprecation") static int firstDayOfWeek(int year, int month) { return (6 + new Date(year - 1900, month - 1, 1).getDay()) % 7; } @SuppressWarnings("deprecation") static int daysInMonth(int year, int month) { return new Date(year + (month == 12 ? 1 : 0) - 1900, (month == 12 ? 1 : month + 1) - 1, 0).getDate(); } @SuppressWarnings("deprecation") static int weekNumber(int year, int month) { Date d = new Date(year - 1900, month - 1, 1); while (d.getDay() != CalendarUtil.getStartingDayOfWeek()) d.setDate(d.getDate() - 1); int y = d.getYear(); int week = 0; while (d.getYear() == y) { d.setDate(d.getDate() - 7); week += 1; } return week; } static int startingDayOfWeek() { return (6 + CalendarUtil.getStartingDayOfWeek()) % 7; } private class SingleMonth extends AbsolutePanel { @SuppressWarnings("deprecation") SingleMonth(String title, Date date, int slot) { date.setDate(1); int year = Integer.parseInt(DateTimeFormat.getFormat("yyyy").format(date)); int month = Integer.parseInt(DateTimeFormat.getFormat("MM").format(date)); int firstDayOfWeek = (6 + date.getDay()) % 7; int nrDays = daysInMonth(year, month); int firstWeekNumber = weekNumber(year, month); addStyleName("month"); if (title != null) { P p = new P("title"); p.setText(title); add(p); } P box = new P("box"); add(box); P header = new P("row"); box.add(header); P corner = new P("cell", "corner"); header.add(corner); for (int i = 0; i < 7; i++) { P h = new P("cell", "dow"); h.setText(CONSTANTS.days()[(i + startingDayOfWeek()) % 7]); header.add(h); } int weekNumber = firstWeekNumber; P line = new P("row"); box.add(line); P week = new P("cell", "week"); week.setText(String.valueOf(weekNumber++)); line.add(week); int idx = 0; int blanks = (firstDayOfWeek + 7 - startingDayOfWeek()) % 7; for (int i = 0; i < blanks; i++) { line.add(new P("cell", (i + 1 == blanks ? "last-blank" : "blank"))); idx++; } for (int i = 1; i <= nrDays; i++) { if (i > 1 && idx % 7 == 0) { if (idx == 7 && month == 1 && weekNumber > 50) weekNumber = 1; line = new P("row"); box.add(line); week = new P("cell", "week"); week.setText(String.valueOf(weekNumber++)); line.add(week); } int day = CalendarUtil.getDaysBetween(iModel.getFirstDate(), date); PeriodInterface period = iModel.getPeriod(day, slot); D d = new D(day, slot, date, period); line.add(d); idx++; date = CalendarUtil.copyDate(date); CalendarUtil.addDaysToDate(date, 1); } } } static Date getDate(Date firstDate, int offset) { Date d = new Date(firstDate.getTime()); if (offset != 0) CalendarUtil.addDaysToDate(d, offset); return d; } protected void render() { iPanel.clear(); iCells.clear(); if (iModel.getExamType().isFinal() || !CONSTANTS.displayMidtermPeriodPreferencesAsCalendar()) { iPanel.setStyleName("unitime-RoomSharingWidget"); DateTimeFormat f1 = DateTimeFormat.getFormat(CONSTANTS.examPeriodPreferenceDateFormat()[0]); DateTimeFormat f2 = DateTimeFormat.getFormat(CONSTANTS.examPeriodPreferenceDateFormat()[1]); DateTimeFormat fm = DateTimeFormat.getFormat("MMMM yyyy"); P horizonal = new P("horizontal"); horizonal.add(iHorizontal); iPanel.add(horizonal); boolean splitByMonths = iModel.getDays().size() > 15; P container = null; if (splitByMonths) { container = new P("container"); iPanel.add(container); } Set<String> months = new HashSet<String>(); while (true) { TreeSet<Integer> days = iModel.getDays(); String month = null; if (splitByMonths) { days = new TreeSet<Integer>(); for (int day : iModel.getDays()) { Date date = getDate(iModel.getFirstDate(), day); String m = fm.format(date); if (m.equals(month)) { days.add(day); } else if (month == null && months.add(m)) { month = m; days.add(day); } } if (month == null) break; } P table = new P(splitByMonths ? "intable" : "table"); if (splitByMonths) { container.add(table); P title = new P("title"); title.setText(month); table.add(title); } else { iPanel.add(table); } P box = new P("box"); table.add(box); P header = new P("row"); box.add(header); P corner = new P("cell", "corner", isEditable() ? "clickable" : null); corner.setHTML(MESSAGES.roomSharingCorner()); header.add(corner); final List<Cell> thisPage = new ArrayList<Cell>(); if (isHorizontal()) { if (container != null) container.addStyleName("orientation-horizontal"); final Map<Integer, List<Cell>> thisSlot = new HashMap<Integer, List<Cell>>(); for (int slot : iModel.getSlots()) { P p = new P("cell", "time", isEditable() ? "clickable" : null); p.setHTML(MESSAGES.roomSharingTimeHeader(slot2short(slot), slot2short(slot + iModel.getLength(slot)))); final List<Cell> t = new ArrayList<Cell>(); thisSlot.put(slot, t); header.add(p); if (isEditable()) p.addMouseDownHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { for (Cell d : t) d.setOption(iPreference); } }); } for (int day : days) { P line = new P("row"); box.add(line); P d = new P("cell", "day", isEditable() ? "clickable" : null); Date date = getDate(iModel.getFirstDate(), day); d.setHTML(f1.format(date) + "<br>" + f2.format(date)); line.add(d); final List<Cell> thisDay = new ArrayList<Cell>(); for (int slot : iModel.getSlots()) { Cell p = new Cell(day, slot, date, iModel.getPeriod(day, slot)); line.add(p); thisSlot.get(slot).add(p); thisPage.add(p); thisDay.add(p); iCells.add(p); } if (isEditable()) d.addMouseDownHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { for (Cell d : thisDay) d.setOption(iPreference); } }); } } else { if (container != null) container.addStyleName("orientation-vertical"); final Map<Integer, List<Cell>> thisDay = new HashMap<Integer, List<Cell>>(); for (int day : days) { P p = new P("cell", "time", isEditable() ? "clickable" : null); Date date = getDate(iModel.getFirstDate(), day); p.setHTML(f1.format(date) + "<br>" + f2.format(date)); final List<Cell> t = new ArrayList<Cell>(); thisDay.put(day, t); header.add(p); if (isEditable()) p.addMouseDownHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { for (Cell d : t) d.setOption(iPreference); } }); } for (int slot : iModel.getSlots()) { P line = new P("row"); box.add(line); P d = new P("cell", "day", isEditable() ? "clickable" : null); d.setHTML(MESSAGES.roomSharingTimeHeader(slot2short(slot), slot2short(slot + iModel.getLength(slot)))); line.add(d); final List<Cell> thisSlot = new ArrayList<Cell>(); for (int day : days) { Date date = getDate(iModel.getFirstDate(), day); Cell p = new Cell(day, slot, date, iModel.getPeriod(day, slot)); line.add(p); thisSlot.add(p); thisPage.add(p); thisDay.get(day).add(p); iCells.add(p); } if (isEditable()) d.addMouseDownHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { for (Cell d : thisSlot) d.setOption(iPreference); } }); } } if (isEditable()) corner.addMouseDownHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { for (Cell d : thisPage) d.setOption(iPreference); } }); if (!splitByMonths) break; } } else { iPanel.setStyleName("unitime-DateSelector"); DateTimeFormat format = DateTimeFormat.getFormat("MMMM yyyy"); P table = new P(); table.getElement().getStyle().setProperty("display", "inline-table"); iPanel.add(table); for (int slot : iModel.getSlots()) { String last = null; P row = new P(); row.getElement().getStyle().setProperty("display", "table-row"); table.add(row); SingleMonth m = null; for (int day : iModel.getDays()) { Date d = getDate(iModel.getFirstDate(), day); if (format.format(d).equals(last)) continue; last = format.format(d); m = new SingleMonth(format.format(d) + " (" + slot2short(slot) + " - " + slot2short(slot + iModel.getLength(slot)) + ")", d, slot); m.getElement().getStyle().setProperty("display", "table-cell"); row.add(m); } } } P legend = new P("legend"); iPanel.add(legend); P box = new P("box"); legend.add(box); iSelectedIcon = null; iSelectedTitle = null; for (final PreferenceInterface option : iModel.getPreferences()) { final P line = new P("row"); final P icon = new P("cell", isEditable(option) ? "clickable" : null); if (box.getWidgetCount() == 0) icon.addStyleName("first"); icon.getElement().getStyle().setBackgroundColor(option.getColor()); line.add(icon); final P title = new P("title", isEditable(option) ? "editable-title" : null); title.setHTML(option.getName()); line.add(title); if (isEditable(option) && option.equals(iPreference)) { icon.addStyleName("selected"); title.addStyleName("selected-title"); iSelectedIcon = icon; iSelectedTitle = title; } if (isEditable(option)) { MouseDownHandler md = new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { if (iModel.isReqConfirmation()) { if (option.getCode().equals("R")) { if (iModel.hasPreference()) UniTimeConfirmationDialog.alert(MESSAGES.warnPreferenceUseRequired()); } else if (!option.getCode().equals("0")) { if (iModel.hasRequired()) UniTimeConfirmationDialog.alert(MESSAGES.warnPreferenceUseNotRequired()); } } iPreference = option; iModel.setSelectedPreference(option); if (iSelectedIcon != null) iSelectedIcon.removeStyleName("selected"); if (iSelectedTitle != null) iSelectedTitle.removeStyleName("selected-title"); icon.addStyleName("selected"); title.addStyleName("selected-title"); iSelectedIcon = icon; iSelectedTitle = title; } }; icon.addMouseDownHandler(md); title.addMouseDownHandler(md); } box.add(line); } } @Override public HandlerRegistration addValueChangeHandler(ValueChangeHandler<PeriodPreferenceModel> handler) { return addHandler(handler, ValueChangeEvent.getType()); } @Override public PeriodPreferenceModel getValue() { return getModel(); } @Override public void setValue(PeriodPreferenceModel value) { setValue(value, false); } @Override public void setValue(PeriodPreferenceModel value, boolean fireEvents) { setModel(value); if (fireEvents) ValueChangeEvent.fire(this, getValue()); } public void insert(final RootPanel panel) { String pattern = null; if (panel.getElement().getFirstChildElement() != null) { pattern = Hidden.wrap(panel.getElement().getFirstChildElement()).getValue(); } else { pattern = panel.getElement().getInnerText().trim(); } final Long examTypeId = Long.valueOf(pattern.substring(0, pattern.indexOf(':'))); ; RPC.execute(RoomInterface.PeriodPreferenceRequest.loadForExam(null, examTypeId), new AsyncCallback<PeriodPreferenceModel>() { @Override public void onFailure(Throwable caught) { UniTimeNotifications.error(caught); } @Override public void onSuccess(final PeriodPreferenceModel model) { if (panel.getElement().getFirstChildElement() != null) { final Hidden pattern = Hidden.wrap(panel.getElement().getFirstChildElement()); model.setPattern(pattern.getValue()); addValueChangeHandler(new ValueChangeHandler<PeriodPreferenceModel>() { @Override public void onValueChange(ValueChangeEvent<PeriodPreferenceModel> event) { pattern.setValue(event.getValue().getPattern()); } }); iEditable = true; } else { String pattern = panel.getElement().getInnerText().trim(); panel.getElement().setInnerText(null); model.setPattern(pattern); iEditable = false; } setModel(model); panel.add(PeriodPreferencesWidget.this); panel.setVisible(true); } }); } }