-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
DateTimeBox.java
357 lines (328 loc) · 13.7 KB
/
DateTimeBox.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
// This file is part of OpenTSDB.
// Copyright (C) 2010-2012 The OpenTSDB Authors.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 2.1 of the License, or (at your
// option) any later version. This program is distributed in the hope that it
// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details. You should have received a copy
// of the GNU Lesser General Public License along with this program. If not,
// see <http://www.gnu.org/licenses/>.
package tsd.client;
import java.util.Date;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.datepicker.client.DateBox;
import com.google.gwt.user.datepicker.client.DatePicker;
/**
* A {@link DateBox} with support for time.
* <p>
* This class is unnecessarily complicated because {@link DateBox} wasn't
* designed in an extensible way (semi-purposefully). A thread gwt-contrib
* titled "DatePicker DatePickerComponent protected ?" from 2008 shows that
* back then they were working on an extensible {@link DateBox} and
* {@link DatePicker} for GWT 2, but as of Sep 2010 this hasn't happened.
* Their suggestion to copy-paste-hack the code is unacceptable so instead
* we go through a few hoops to make this work.
*/
final class DateTimeBox extends DateBox {
private static final DateTimeFormat HHMM_FORMAT =
DateTimeFormat.getFormat("HH:mm");
private static final DefaultFormat DATE_FORMAT =
new DefaultFormat(DateTimeFormat.getFormat("yyyy/MM/dd-HH:mm:ss")) {
/** Adds support for some human readable dates ("1d ago", "10:30"). */
@Override
public Date parse(final DateBox box,
final String text,
final boolean report_error) {
if (text.endsWith(" ago")) { // "1d ago" and such
int interval;
final int lastchar = text.length() - 5;
try {
interval = Integer.parseInt(text.substring(0, lastchar));
} catch (NumberFormatException e) {
setError(box);
return null;
}
if (interval <= 0) {
setError(box);
return null;
}
switch (text.charAt(lastchar)) {
case 's': break; // seconds
case 'm': interval *= 60; break; // minutes
case 'h': interval *= 3600; break; // hours
case 'd': interval *= 3600 * 24; break; // days
case 'w': interval *= 3600 * 24 * 7; break; // weeks
case 'y': interval *= 3600 * 24 * 365; break; // years
}
final Date d = new Date();
d.setTime(d.getTime() - interval * 1000);
return d;
} else if (text.length() == 5) { // "HH:MM"
try {
return HHMM_FORMAT.parse(text);
} catch (IllegalArgumentException ignored) {
setError(box);
return null;
}
}
return super.parse(box, text, report_error);
}
private void setError(final DateBox box) {
box.addStyleName("dateBoxFormatError");
}
};
public DateTimeBox() {
super(new DateTimePicker(), null, DATE_FORMAT);
((DateTimePicker) getDatePicker()).setDateTimeBox(this);
final TextBox textbox = getTextBox();
// Chrome 7.0.5xx versions, Safari 5.0.x and similar render a text box
// that's too small for 19 characters (WTF?). So we ask for space for
// an extra 2 characters. On Firefox the text box's width is computed
// properly, so it simply appears slightly wider than necessary.
textbox.setVisibleLength(19 + 2);
textbox.setMaxLength(19);
}
/**
* A {@link DatePicker} with a customized UI for time support.
*/
private static final class DateTimePicker extends DatePicker {
/** DateTimeBox this picker belongs to. */
private DateTimeBox box;
/** A grid in which we put some buttons we may need to update. */
private Grid hours_minutes;
public DateTimePicker() {
}
/**
* Sets the {@link DateTimeBox} this {@link DateTimePicker} belongs to.
* This <b>must</b> be called before using this object.
*/
void setDateTimeBox(final DateTimeBox box) {
this.box = box;
}
/**
* Sets the date of the {@link DateBox} to the given {@link Date}.
*/
private void setDate(final Date d) {
refreshAll();
box.setValue(d);
// Put the focus back on the text box to make it easier for the
// user to manually edit the field.
box.getTextBox().setFocus(true);
}
/**
* Returns a new button that shifts the date when clicked.
* @param seconds How many seconds to shift.
* @param label The label to put on the button.
*/
private PushButton newShiftDateButton(final int seconds,
final String label) {
final PushButton button = new PushButton(label);
button.setStyleName(seconds < 0 ? "datePickerPreviousButton"
: "datePickerNextButton");
button.addClickHandler(new ClickHandler() {
public void onClick(final ClickEvent event) {
Date d = box.getValue();
if (d == null) {
if (seconds >= 0) {
return;
}
d = new Date();
}
d.setTime(d.getTime() + seconds * 1000);
d.setSeconds(0);
setDate(d);
}
});
return button;
}
/**
* Returns a new button that sets the hours when clicked.
* @param hours An hour of the day (0-23).
* @param label The label to put on the button.
*/
private PushButton newSetHoursButton(final int hours) {
final PushButton button = new PushButton(Integer.toString(hours));
button.addClickHandler(new ClickHandler() {
public void onClick(final ClickEvent event) {
@SuppressWarnings(/* GWT requires us to use Date */{"deprecation"})
Date d = box.getValue();
if (d == null) {
d = new Date();
d.setMinutes(0);
}
d.setHours(hours);
d.setSeconds(0);
setDate(d);
}
});
return button;
}
/**
* Returns a new button that sets the minutes when clicked.
* @param minutes A value for minutes (0-59).
* @param label The label to put on the button.
*/
private PushButton newSetMinutesButton(final int minutes,
final String label) {
final PushButton button = new PushButton(label);
button.addClickHandler(new ClickHandler() {
public void onClick(final ClickEvent event) {
@SuppressWarnings(/* GWT requires us to use Date */{"deprecation"})
Date d = box.getValue();
if (d == null) {
d = new Date();
}
d.setMinutes(minutes);
d.setSeconds(0);
setDate(d);
}
});
return button;
}
/** Rebuilds parts of the UI with buttons to set AM hours. */
private void setupAmUI() {
hours_minutes.setWidget(0, 1, newSetHoursButton(0));
hours_minutes.setWidget(0, 2, newSetHoursButton(1));
hours_minutes.setWidget(0, 3, newSetHoursButton(2));
hours_minutes.setWidget(0, 4, newSetHoursButton(3));
hours_minutes.setWidget(0, 5, newSetHoursButton(4));
hours_minutes.setWidget(0, 6, newSetHoursButton(5));
hours_minutes.setWidget(1, 1, newSetHoursButton(6));
hours_minutes.setWidget(1, 2, newSetHoursButton(7));
hours_minutes.setWidget(1, 3, newSetHoursButton(8));
hours_minutes.setWidget(1, 4, newSetHoursButton(9));
hours_minutes.setWidget(1, 5, newSetHoursButton(10));
hours_minutes.setWidget(1, 6, newSetHoursButton(11));
}
/** Rebuilds parts of the UI with buttons to set PM hours. */
private void setupPmUI() {
hours_minutes.setWidget(0, 1, newSetHoursButton(12));
hours_minutes.setWidget(0, 2, newSetHoursButton(13));
hours_minutes.setWidget(0, 3, newSetHoursButton(14));
hours_minutes.setWidget(0, 4, newSetHoursButton(15));
hours_minutes.setWidget(0, 5, newSetHoursButton(16));
hours_minutes.setWidget(0, 6, newSetHoursButton(17));
hours_minutes.setWidget(1, 1, newSetHoursButton(18));
hours_minutes.setWidget(1, 2, newSetHoursButton(19));
hours_minutes.setWidget(1, 3, newSetHoursButton(20));
hours_minutes.setWidget(1, 4, newSetHoursButton(21));
hours_minutes.setWidget(1, 5, newSetHoursButton(22));
hours_minutes.setWidget(1, 6, newSetHoursButton(23));
}
/** Sets up the custom UI of the date picker. */
@Override
protected void setup() {
final HorizontalPanel panel = new HorizontalPanel();
initWidget(panel);
setStyleName(panel.getElement(), "gwt-DatePicker");
{
final VerticalPanel vbox = new VerticalPanel();
setStyleName("gwt-DatePicker");
vbox.add(super.getMonthSelector());
vbox.add(super.getView());
panel.add(vbox);
}
{
// This vbox contains all of the "extra" panel on the side
// of the calendar view.
final VerticalPanel vbox = new VerticalPanel();
setStyleName(vbox.getElement(), "datePickerMonthSelector");
final PushButton now = new PushButton("now");
now.setStyleName("datePickerNextButton");
now.addClickHandler(new ClickHandler() {
public void onClick(final ClickEvent event) {
box.setValue(new Date());
}
});
{
final Grid grid = new Grid(2, 9);
grid.setWidget(0, 0, newShiftDateButton(-3600, "1h"));
grid.setWidget(0, 1, newShiftDateButton(-600, "10m"));
grid.setWidget(0, 2, newShiftDateButton(-60, "1m"));
grid.setWidget(0, 3, new InlineHTML("‹"));
grid.setWidget(0, 4, now);
grid.setWidget(0, 5, new InlineHTML("›"));
grid.setWidget(0, 6, newShiftDateButton(+60, "1m"));
grid.setWidget(0, 7, newShiftDateButton(+600, "10m"));
grid.setWidget(0, 8, newShiftDateButton(+3600, "1h"));
grid.setWidget(1, 0, newShiftDateButton(-86400 * 30, "30d"));
grid.setWidget(1, 1, newShiftDateButton(-86400 * 7, "1w"));
grid.setWidget(1, 2, newShiftDateButton(-86400, "1d"));
grid.setWidget(1, 3, new InlineHTML("«"));
grid.setWidget(1, 4, new InlineHTML(" "));
grid.setWidget(1, 5, new InlineHTML("»"));
grid.setWidget(1, 6, newShiftDateButton(+86400, "1d"));
grid.setWidget(1, 7, newShiftDateButton(+86400 * 7, "1w"));
grid.setWidget(1, 8, newShiftDateButton(+86400 * 30, "30d"));
final CellFormatter formatter = grid.getCellFormatter();
formatter.setWidth(0, 4, "100%");
formatter.setWidth(1, 4, "100%");
vbox.add(grid);
}
{
hours_minutes = new Grid(4, 8);
setupAmUI();
hours_minutes.setWidget(0, 0, new InlineLabel("HH"));
final PushButton set_am = new PushButton("AM");
set_am.addClickHandler(new ClickHandler() {
public void onClick(final ClickEvent event) {
setupAmUI();
}
});
hours_minutes.setWidget(0, 7, set_am);
final PushButton set_pm = new PushButton("PM");
set_pm.addClickHandler(new ClickHandler() {
public void onClick(final ClickEvent event) {
setupPmUI();
}
});
hours_minutes.setWidget(1, 7, set_pm);
hours_minutes.setWidget(2, 0, new InlineLabel("MM"));
hours_minutes.setWidget(2, 1, newSetMinutesButton(0, "00"));
hours_minutes.setWidget(2, 2, newSetMinutesButton(10, "10"));
hours_minutes.setWidget(2, 3, newSetMinutesButton(20, "20"));
hours_minutes.setWidget(2, 4, newSetMinutesButton(30, "30"));
hours_minutes.setWidget(2, 5, newSetMinutesButton(40, "40"));
hours_minutes.setWidget(2, 6, newSetMinutesButton(50, "50"));
vbox.add(hours_minutes);
}
{
final HorizontalPanel hbox = new HorizontalPanel();
hbox.add(new InlineLabel("UNIX timestamp:"));
final ValidatedTextBox ts = new ValidatedTextBox();
ts.setValidationRegexp("^(|[1-9][0-9]{0,9})$");
ts.setVisibleLength(10);
ts.setMaxLength(10);
final EventsHandler handler = new EventsHandler() {
protected <H extends EventHandler> void onEvent(final DomEvent<H> event) {
final Date d = new Date(Integer.parseInt(ts.getValue()) * 1000L);
box.setValue(d, true);
}
};
ts.addBlurHandler(handler);
ts.addKeyPressHandler(handler);
hbox.add(ts);
vbox.add(hbox);
}
vbox.setHeight("100%");
panel.add(vbox);
panel.setCellHeight(vbox, "100%");
}
}
}
}