In barcode generaotor (zxing.appspot.com), generate barcode upon pressing enter....
[zxing.git] / zxing.appspot.com / generator / src / com / google / zxing / web / generator / client / CalendarEventGenerator.java
1 /*
2  * Copyright (C) 2008 ZXing authors
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.google.zxing.web.generator.client;
18
19 import com.google.gwt.event.dom.client.KeyPressHandler;
20 import com.google.gwt.i18n.client.DateTimeFormat;
21 import com.google.gwt.user.client.DOM;
22 import com.google.gwt.user.client.Element;
23 import com.google.gwt.user.client.ui.ChangeListener;
24 import com.google.gwt.user.client.ui.CheckBox;
25 import com.google.gwt.user.client.ui.ClickListener;
26 import com.google.gwt.user.client.ui.Grid;
27 import com.google.gwt.user.client.ui.ListBox;
28 import com.google.gwt.user.client.ui.TextBox;
29 import com.google.gwt.user.client.ui.Widget;
30 import com.google.gwt.widgetideas.client.event.ChangeEvent;
31 import com.google.gwt.widgetideas.client.event.ChangeHandler;
32 import com.google.gwt.widgetideas.datepicker.client.DateBox;
33 import com.google.gwt.widgetideas.datepicker.client.TimePicker;
34 import com.google.zxing.web.generator.client.TimeZoneList.TimeZoneInfo;
35
36 import java.util.Date;
37
38 /**
39  * A Generator for calendar events. Output is in VCal format.
40  * 
41  * @author Yohann Coppel
42  */
43 public class CalendarEventGenerator implements GeneratorSource {
44   public static final String[] FULL_DAY_ONLY_IDS = { "fullDayOnlyInfo1",
45       "fullDayOnlyInfo2", "fullDayOnlyInfo3", "fullDayOnlyInfo4" };
46   private static final long ONE_HOUR = 60L * 60 * 1000;
47
48   Grid table = null;
49   TextBox eventName = new TextBox();
50   CheckBox fullDay = new CheckBox();
51   DateBox datePicker1 = new DateBox();
52   DateBox datePicker2 = new DateBox();
53   TimePicker timePicker1 = new TimePicker(new Date(), DateTimeFormat
54       .getFormat("a"), DateTimeFormat.getFormat("hh"), DateTimeFormat
55       .getFormat("mm"), null);
56   TimePicker timePicker2 = new TimePicker(new Date(), DateTimeFormat
57       .getFormat("a"), DateTimeFormat.getFormat("hh"), DateTimeFormat
58       .getFormat("mm"), null);
59   CheckBox summerTime = new CheckBox();
60   ListBox timeZones = new ListBox();
61   Date timePicker1PreviousDate = null;
62
63   public CalendarEventGenerator(final ChangeListener listener,
64       KeyPressHandler keyListener) {
65     eventName.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED);
66     eventName.addChangeListener(listener);
67     eventName.addKeyPressHandler(keyListener);
68     datePicker1.setAnimationEnabled(true);
69     datePicker2.setAnimationEnabled(true);
70     timePicker2
71         .setDateTime(addMilliseconds(timePicker1.getDateTime(), ONE_HOUR));
72     timePicker1PreviousDate = timePicker1.getDateTime();
73
74     buildTimeZoneList();
75     timeZones.setSelectedIndex(25);
76     timeZones.addKeyPressHandler(keyListener);
77     timePicker1.addChangeHandler(new ChangeHandler<Date>() {
78       public void onChange(ChangeEvent<Date> event) {
79         Date time = timePicker1PreviousDate;
80         Date time1 = timePicker1.getDateTime();
81         Date time2 = timePicker2.getDateTime();
82         if (time2.after(time)) {
83           // keep the same time difference if the interval is valid.
84           long diff = time2.getTime() - time.getTime();
85           timePicker2.setDateTime(addMilliseconds(time1, diff));
86         } else {
87           // otherwise erase the end date and set it to startdate + one hour.
88           timePicker2.setDateTime(addMilliseconds(time, ONE_HOUR));
89         }
90         // no need to call onChange for timePicker1, since it will be called
91         // for timePicker2 when changes are made.
92         // listener.onChange(timePicker1);
93         timePicker1PreviousDate = time1;
94       }
95     });
96     timePicker2.addChangeHandler(new ChangeHandler<Date>() {
97       public void onChange(ChangeEvent<Date> event) {
98         listener.onChange(timePicker2);
99       }
100     });
101   }
102
103   private void buildTimeZoneList() {
104     for (TimeZoneInfo info : TimeZoneList.TIMEZONES) {
105       timeZones.addItem(info.GMTRelative + ' ' + info.abreviation, String.valueOf(info.gmtDiff));
106     }
107   }
108
109   public String getName() {
110     return "Calendar event";
111   }
112
113   public Grid getWidget() {
114     if (table != null) {
115       return table;
116     }
117     datePicker1.getDatePicker().setSelectedDate(new Date());
118     datePicker2.getDatePicker().setSelectedDate(new Date());
119     table = new Grid(8, 2);
120
121     table.setText(0, 0, "All day event");
122     table.setWidget(0, 1, fullDay);
123
124     table.setText(1, 0, "Event title");
125     table.setWidget(1, 1, eventName);
126
127     table.setText(2, 0, "Start date");
128     table.setWidget(2, 1, datePicker1);
129
130     table.setText(3, 0, "Time");
131     table.setWidget(3, 1, timePicker1);
132
133     table.setText(4, 0, "End date");
134     table.setWidget(4, 1, datePicker2);
135
136     table.setText(5, 0, "Time");
137     table.setWidget(5, 1, timePicker2);
138
139     table.setText(6, 0, "Time zone");
140     table.setWidget(6, 1, timeZones);
141
142     table.setText(7, 0, "Daylight savings");
143     table.setWidget(7, 1, summerTime);
144
145     table.getRowFormatter().getElement(3).setId(FULL_DAY_ONLY_IDS[0]);
146     table.getRowFormatter().getElement(5).setId(FULL_DAY_ONLY_IDS[1]);
147     table.getRowFormatter().getElement(6).setId(FULL_DAY_ONLY_IDS[2]);
148     table.getRowFormatter().getElement(7).setId(FULL_DAY_ONLY_IDS[3]);
149
150     fullDay.addClickListener(new ClickListener() {
151       public void onClick(Widget sender) {
152         CheckBox cb = (CheckBox) sender;
153         setFullDay(cb.isChecked());
154       }
155     });
156
157     return table;
158   }
159
160   private void setFullDay(boolean fullDay) {
161     for (String s : FULL_DAY_ONLY_IDS) {
162       Element element = DOM.getElementById(s);
163       String style = fullDay ? "none" : "";
164       DOM.setStyleAttribute(element, "display", style);
165     }
166   }
167
168   public String getText() throws GeneratorException {
169     String eventName = getEventNameField();
170     String dates = getDateTimeFields();
171     StringBuilder output = new StringBuilder();
172     output.append("BEGIN:VEVENT\r\n");
173     output.append(eventName);
174     output.append(dates);
175     output.append("END:VEVENT\r\n");
176     return output.toString();
177   }
178
179   private String getEventNameField() throws GeneratorException {
180     String inputName = eventName.getText();
181     if (inputName.length() < 1) {
182       throw new GeneratorException("Event name must be at least 1 character.");
183     }
184     if (inputName.contains("\n")) {
185       throw new GeneratorException(
186           "Event name should not contain \\n characters.");
187     }
188     return "SUMMARY:" + inputName + "\r\n";
189   }
190
191   private String getDateTimeFields() throws GeneratorException {
192     if (fullDay.isChecked()) {
193       return getFullDayDateFields();
194     }
195     return getDateTimeValues();
196   }
197
198   private String getFullDayDateFields() throws GeneratorException {
199     Date date1 = datePicker1.getDatePicker().getSelectedDate();
200     Date date2 = datePicker2.getDatePicker().getSelectedDate();
201     if (null == date1 || null == date2) {
202       throw new GeneratorException("Start and end dates must be set.");
203     }
204     if (date1.after(date2)) {
205       throw new GeneratorException("Ending date is after starting date.");
206     }
207     DateTimeFormat isoFormatter = DateTimeFormat.getFormat("yyyyMMdd");
208     StringBuilder output = new StringBuilder();
209     output.append("DTSTART:");
210     output.append(isoFormatter.format(date1));
211     output.append("\r\n");
212     output.append("DTEND:");
213     output.append(isoFormatter.format(date2));
214     output.append("\r\n");
215     return output.toString();
216   }
217
218   private String getDateTimeValues() throws GeneratorException {
219     Date date1 = datePicker1.getDatePicker().getSelectedDate();
220     Date date2 = datePicker2.getDatePicker().getSelectedDate();
221     Date time1 = timePicker1.getDateTime();
222     Date time2 = timePicker2.getDateTime();
223     if (null == date1 || null == date2 || null == time1 || null == time2) {
224       throw new GeneratorException("Start and end dates/times must be set.");
225     }
226     String timezoneDelta = timeZones.getValue(timeZones.getSelectedIndex());
227     long diffTimeZone = Long.parseLong(timezoneDelta);
228     if (summerTime.isChecked()) {
229       diffTimeZone += ONE_HOUR;
230     }
231     Date dateTime1 = addMilliseconds(mergeDateAndTime(date1, time1),
232         -diffTimeZone);
233     Date dateTime2 = addMilliseconds(mergeDateAndTime(date2, time2),
234         -diffTimeZone);
235     if (dateTime1.after(dateTime2)) {
236       throw new GeneratorException("Ending date is after starting date.");
237     }
238     DateTimeFormat isoFormatter = DateTimeFormat
239         .getFormat("yyyyMMdd'T'HHmmss'Z'");
240     StringBuilder output = new StringBuilder();
241     output.append("DTSTART:");
242     output.append(isoFormatter.format(dateTime1));
243     output.append("\r\n");
244     output.append("DTEND:");
245     output.append(isoFormatter.format(dateTime2));
246     output.append("\r\n");
247     return output.toString();
248   }
249
250   private static Date mergeDateAndTime(Date date, Date time) {
251     // Is that the only ugly way to do with GWT ? given that we don't
252     // have java.util.Calendar for instance
253     DateTimeFormat extractDate = DateTimeFormat.getFormat("yyyyMMdd");
254     DateTimeFormat extractTime = DateTimeFormat.getFormat("HHmm");
255     DateTimeFormat merger = DateTimeFormat.getFormat("yyyyMMddHHmmss");
256     String d = extractDate.format(date);
257     String t = extractTime.format(time) + "00";
258     return merger.parse(d + t);
259   }
260
261   public void validate(Widget widget) throws GeneratorException {
262     if (widget == eventName) {
263       getEventNameField();
264     } else if (widget == datePicker1 || widget == timePicker1 || widget == datePicker2
265         || widget == timePicker2) {
266       getDateTimeFields();
267     }
268   }
269
270   private static Date addMilliseconds(Date time1, long milliseconds) {
271     return new Date(time1.getTime() + milliseconds);
272   }
273
274   public void setFocus() {
275     eventName.setFocus(true);
276   }
277 }