2 * Copyright (C) 2008 ZXing authors
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.google.zxing.web.generator.client;
19 import com.google.gwt.i18n.client.DateTimeFormat;
20 import com.google.gwt.user.client.DOM;
21 import com.google.gwt.user.client.Element;
22 import com.google.gwt.user.client.ui.ChangeListener;
23 import com.google.gwt.user.client.ui.CheckBox;
24 import com.google.gwt.user.client.ui.ClickListener;
25 import com.google.gwt.user.client.ui.Grid;
26 import com.google.gwt.user.client.ui.ListBox;
27 import com.google.gwt.user.client.ui.TextBox;
28 import com.google.gwt.user.client.ui.Widget;
29 import com.google.gwt.widgetideas.client.event.ChangeEvent;
30 import com.google.gwt.widgetideas.client.event.ChangeHandler;
31 import com.google.gwt.widgetideas.datepicker.client.DateBox;
32 import com.google.gwt.widgetideas.datepicker.client.TimePicker;
33 import com.google.zxing.web.generator.client.TimeZoneList.TimeZoneInfo;
35 import java.util.Date;
38 * A Generator for calendar events. Output is in VCal format.
40 * @author Yohann Coppel
42 public class CalendarEventGenerator implements GeneratorSource {
43 public static final String[] FULL_DAY_ONLY_IDS = { "fullDayOnlyInfo1",
44 "fullDayOnlyInfo2", "fullDayOnlyInfo3", "fullDayOnlyInfo4" };
45 private static final long ONE_HOUR = 60L * 60 * 1000;
48 TextBox eventName = new TextBox();
49 CheckBox fullDay = new CheckBox();
50 DateBox datePicker1 = new DateBox();
51 DateBox datePicker2 = new DateBox();
52 TimePicker timePicker1 = new TimePicker(new Date(), DateTimeFormat
53 .getFormat("a"), DateTimeFormat.getFormat("hh"), DateTimeFormat
54 .getFormat("mm"), null);
55 TimePicker timePicker2 = new TimePicker(new Date(), DateTimeFormat
56 .getFormat("a"), DateTimeFormat.getFormat("hh"), DateTimeFormat
57 .getFormat("mm"), null);
58 CheckBox summerTime = new CheckBox();
59 ListBox timeZones = new ListBox();
60 Date timePicker1PreviousDate = null;
62 public CalendarEventGenerator(final ChangeListener listener) {
63 eventName.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED);
64 eventName.addChangeListener(listener);
65 datePicker1.setAnimationEnabled(true);
66 datePicker2.setAnimationEnabled(true);
68 .setDateTime(addMilliseconds(timePicker1.getDateTime(), ONE_HOUR));
69 timePicker1PreviousDate = timePicker1.getDateTime();
72 timeZones.setSelectedIndex(25);
73 timePicker1.addChangeHandler(new ChangeHandler<Date>() {
74 public void onChange(ChangeEvent<Date> event) {
75 Date time = timePicker1PreviousDate;
76 Date time1 = timePicker1.getDateTime();
77 Date time2 = timePicker2.getDateTime();
78 if (time2.after(time)) {
79 // keep the same time difference if the interval is valid.
80 long diff = time2.getTime() - time.getTime();
81 timePicker2.setDateTime(addMilliseconds(time1, diff));
83 // otherwise erase the end date and set it to startdate + one hour.
84 timePicker2.setDateTime(addMilliseconds(time, ONE_HOUR));
86 // no need to call onChange for timePicker1, since it will be called
87 // for timePicker2 when changes are made.
88 // listener.onChange(timePicker1);
89 timePicker1PreviousDate = time1;
92 timePicker2.addChangeHandler(new ChangeHandler<Date>() {
93 public void onChange(ChangeEvent<Date> event) {
94 listener.onChange(timePicker2);
99 private void buildTimeZoneList() {
100 for (TimeZoneInfo info : TimeZoneList.TIMEZONES) {
101 timeZones.addItem(info.GMTRelative + ' ' + info.abreviation, String.valueOf(info.gmtDiff));
105 public String getName() {
106 return "Calendar event";
109 public Grid getWidget() {
113 datePicker1.getDatePicker().setSelectedDate(new Date());
114 datePicker2.getDatePicker().setSelectedDate(new Date());
115 table = new Grid(8, 2);
117 table.setText(0, 0, "All day event");
118 table.setWidget(0, 1, fullDay);
120 table.setText(1, 0, "Event title");
121 table.setWidget(1, 1, eventName);
123 table.setText(2, 0, "Start date");
124 table.setWidget(2, 1, datePicker1);
126 table.setText(3, 0, "Time");
127 table.setWidget(3, 1, timePicker1);
129 table.setText(4, 0, "End date");
130 table.setWidget(4, 1, datePicker2);
132 table.setText(5, 0, "Time");
133 table.setWidget(5, 1, timePicker2);
135 table.setText(6, 0, "Time zone");
136 table.setWidget(6, 1, timeZones);
138 table.setText(7, 0, "Daylight savings");
139 table.setWidget(7, 1, summerTime);
141 table.getRowFormatter().getElement(3).setId(FULL_DAY_ONLY_IDS[0]);
142 table.getRowFormatter().getElement(5).setId(FULL_DAY_ONLY_IDS[1]);
143 table.getRowFormatter().getElement(6).setId(FULL_DAY_ONLY_IDS[2]);
144 table.getRowFormatter().getElement(7).setId(FULL_DAY_ONLY_IDS[3]);
146 fullDay.addClickListener(new ClickListener() {
147 public void onClick(Widget sender) {
148 CheckBox cb = (CheckBox) sender;
149 setFullDay(cb.isChecked());
156 private void setFullDay(boolean fullDay) {
157 for (String s : FULL_DAY_ONLY_IDS) {
158 Element element = DOM.getElementById(s);
159 String style = fullDay ? "none" : "";
160 DOM.setStyleAttribute(element, "display", style);
164 public String getText() throws GeneratorException {
165 String eventName = getEventNameField();
166 String dates = getDateTimeFields();
167 StringBuilder output = new StringBuilder();
168 output.append("BEGIN:VEVENT\r\n");
169 output.append(eventName);
170 output.append(dates);
171 output.append("END:VEVENT\r\n");
172 return output.toString();
175 private String getEventNameField() throws GeneratorException {
176 String inputName = eventName.getText();
177 if (inputName.length() < 1) {
178 throw new GeneratorException("Event name must be at least 1 character.");
180 if (inputName.contains("\n")) {
181 throw new GeneratorException(
182 "Event name should not contain \\n characters.");
184 return "SUMMARY:" + inputName + "\r\n";
187 private String getDateTimeFields() throws GeneratorException {
188 if (fullDay.isChecked()) {
189 return getFullDayDateFields();
191 return getDateTimeValues();
194 private String getFullDayDateFields() throws GeneratorException {
195 Date date1 = datePicker1.getDatePicker().getSelectedDate();
196 Date date2 = datePicker2.getDatePicker().getSelectedDate();
197 if (null == date1 || null == date2) {
198 throw new GeneratorException("Start and end dates must be set.");
200 if (date1.after(date2)) {
201 throw new GeneratorException("Ending date is after starting date.");
203 DateTimeFormat isoFormatter = DateTimeFormat.getFormat("yyyyMMdd");
204 StringBuilder output = new StringBuilder();
205 output.append("DTSTART:");
206 output.append(isoFormatter.format(date1));
207 output.append("\r\n");
208 output.append("DTEND:");
209 output.append(isoFormatter.format(date2));
210 output.append("\r\n");
211 return output.toString();
214 private String getDateTimeValues() throws GeneratorException {
215 Date date1 = datePicker1.getDatePicker().getSelectedDate();
216 Date date2 = datePicker2.getDatePicker().getSelectedDate();
217 Date time1 = timePicker1.getDateTime();
218 Date time2 = timePicker2.getDateTime();
219 if (null == date1 || null == date2 || null == time1 || null == time2) {
220 throw new GeneratorException("Start and end dates/times must be set.");
222 String timezoneDelta = timeZones.getValue(timeZones.getSelectedIndex());
223 long diffTimeZone = Long.parseLong(timezoneDelta);
224 if (summerTime.isChecked()) {
225 diffTimeZone += ONE_HOUR;
227 Date dateTime1 = addMilliseconds(mergeDateAndTime(date1, time1),
229 Date dateTime2 = addMilliseconds(mergeDateAndTime(date2, time2),
231 if (dateTime1.after(dateTime2)) {
232 throw new GeneratorException("Ending date is after starting date.");
234 DateTimeFormat isoFormatter = DateTimeFormat
235 .getFormat("yyyyMMdd'T'HHmmss'Z'");
236 StringBuilder output = new StringBuilder();
237 output.append("DTSTART:");
238 output.append(isoFormatter.format(dateTime1));
239 output.append("\r\n");
240 output.append("DTEND:");
241 output.append(isoFormatter.format(dateTime2));
242 output.append("\r\n");
243 return output.toString();
246 private static Date mergeDateAndTime(Date date, Date time) {
247 // Is that the only ugly way to do with GWT ? given that we don't
248 // have java.util.Calendar for instance
249 DateTimeFormat extractDate = DateTimeFormat.getFormat("yyyyMMdd");
250 DateTimeFormat extractTime = DateTimeFormat.getFormat("HHmm");
251 DateTimeFormat merger = DateTimeFormat.getFormat("yyyyMMddHHmmss");
252 String d = extractDate.format(date);
253 String t = extractTime.format(time) + "00";
254 return merger.parse(d + t);
257 public void validate(Widget widget) throws GeneratorException {
258 if (widget == eventName) {
260 } else if (widget == datePicker1 || widget == timePicker1 || widget == datePicker2
261 || widget == timePicker2) {
266 private static Date addMilliseconds(Date time1, long milliseconds) {
267 return new Date(time1.getTime() + milliseconds);
270 public void setFocus() {
271 eventName.setFocus(true);