1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1999-2000 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 import java.awt.*;
28 import java.awt.event.*;
29 import java.text.*;
30 import java.util.*;
31
32 /**
33 * This class creates a dialog box that helps the user enter date and
34 * time with mouse clicks. The dialog box need only be created
35 * once. The Ok and Cancel buttons merely call setVisible with an
36 * argument of false.
37 */
38
39 // The layout will consist of 3 panels: topPanel contains the
40 // different labels and fields. middlePanel contains the buttons
41 // midnight and now. bottomPanel contains the buttons ok, cancel and
42 // help. The last two panels are separated by a LineSeparator.
43
44 public class DateTimeDialog extends Dialog {
45
46 private boolean save;
47
48 private Frame parent;
49
50 private DCPanel dateDCPanel;
51 private DCPanel yearDCPanel;
52 private DCPanel hourDCPanel;
53 private DCPanel minuteDCPanel;
54 private DCPanel secondDCPanel;
55
56 private Choice month;
57
58 private DCCircularTextField date;
59 private DCCircularTextField hour;
60 private DCCircularTextField second;
61 private DCCircularTextField minute;
62 private DCTextField year;
63
64 private Button ok;
65 private Button cancel;
66 private Button help;
67 private Button now;
68 private Button midnight;
69
70 private HelpDialog hd = null;
71
72 private Panel topPanel;
73 private Panel middlePanel;
74 private Panel bottomPanel;
75
76 private GregorianCalendar calendar = null;
77 private static int MONTH_LEN[] = {31, 28, 31, 30, 31, 30, 31,
78 31, 30, 31, 30, 31};
79 private static DateFormat df =
80 DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
81 DateFormat.MEDIUM);
82 private static Toolkit toolkit = Toolkit.getDefaultToolkit();
83
84 // For I18N
85 private static ResourceBundle rb =
86 ResourceBundle.getBundle("GuiResource" /* NOI18N */);
87 private static ResourceBundle hrb =
88 ResourceBundle.getBundle("HelpData" /* NOI18N */);
89
90 /**
91 * Constructor that lays out the componeents and sets the different
92 * event handlers.
93 */
94 public DateTimeDialog(Frame parent, Color background, Color foreground) {
95 super(parent, getString("SEAM Date/Time Helper"), true);
96
97 this.parent = parent;
98
99 setLayout(new GridBagLayout());
100 addLabels();
101 addFields(background, foreground);
102 addDCPanels();
103 addButtons();
104 addFocusListeners();
105 setCurrentTime();
106 setSize(250, 300);
107 setResizable(false);
108
109 addWindowListener(new DCWindowListener());
110 // initializeFocusOnTextField();
111 }
112
113 /**
114 * Adds the labels only
115 */
116 private void addLabels() {
117
118 GridBagConstraints gbc = new GridBagConstraints();
119 gbc.weighty = 1;
120
121 topPanel = new Panel();
122 topPanel.setLayout(new GridBagLayout());
123 gbc.gridwidth = GridBagConstraints.REMAINDER;
124 gbc.fill = GridBagConstraints.BOTH;
125 gbc.anchor = GridBagConstraints.CENTER;
126 gbc.gridx = 0;
127 gbc.gridy = 0;
128 add(topPanel, gbc);
129
130 gbc.fill = GridBagConstraints.NONE;
131 gbc.anchor = GridBagConstraints.EAST;
132 gbc.gridx = 0;
133 gbc.gridwidth = 1;
134
135 gbc.gridy = 0;
136 topPanel.add(new Label(getString("Month")), gbc);
137
138 gbc.gridy = 1;
139 topPanel.add(new Label(getString("Date")), gbc);
140
141 gbc.gridy = 2;
142 topPanel.add(new Label(getString("Year")), gbc);
143
144 gbc.gridy = 3;
145 topPanel.add(new Label(getString("Hour")), gbc);
146
147 gbc.gridy = 4;
148 topPanel.add(new Label(getString("Minute")), gbc);
149
150 gbc.gridy = 5;
151 topPanel.add(new Label(getString("Second")), gbc);
152 }
153
154 /**
155 * Adds the fields that will store the month, year, date, hour,
156 * minute and second.
157 */
158 private void addFields(Color background, Color foreground) {
159
160 GridBagConstraints gbc = new GridBagConstraints();
161 gbc.weighty = 1;
162
163 month = new Choice();
164 initializeMonth();
165
166 date = new DCCircularTextField("1", 2);
167 date.setMinimum(1);
168 date.setBackground(background);
169 date.setForeground(foreground);
170
171 hour = new DCCircularTextField("00", 2);
172 hour.setMaximum(23);
173 hour.setBackground(background);
174 hour.setForeground(foreground);
175 minute = new DCCircularTextField("00", 2);
176 minute.setBackground(background);
177 minute.setForeground(foreground);
178 second = new DCCircularTextField("00", 2);
179 second.setBackground(background);
180 second.setForeground(foreground);
181
182 year = new DCTextField("2000", 4);
183 year.setBackground(background);
184 year.setForeground(foreground);
185
186 Panel tempPanel = new Panel();
187 tempPanel.add(month);
188 gbc.gridwidth = GridBagConstraints.REMAINDER;
189 gbc.fill = GridBagConstraints.HORIZONTAL;
190 gbc.anchor = GridBagConstraints.WEST;
191 gbc.gridx = 1;
192 gbc.gridy = 0;
193 topPanel.add(tempPanel, gbc);
194
195
196 // Remaining fields are in topPanel
197 gbc.gridwidth = 1;
198 gbc.fill = GridBagConstraints.NONE;
199 gbc.gridx = 1;
200
201 gbc.gridy = 1;
202 topPanel.add(date, gbc);
203
204 gbc.gridy = 2;
205 topPanel.add(year, gbc);
206
207 gbc.gridy = 3;
208 topPanel.add(hour, gbc);
209
210 gbc.gridy = 4;
211 topPanel.add(minute, gbc);
212
213 gbc.gridy = 5;
214 topPanel.add(second, gbc);
215
216 }
217
218 // Adds the panels with the +/- buttons for each DCField
219 private void addDCPanels() {
220
221 GridBagConstraints gbc = new GridBagConstraints();
222 gbc.weighty = 1;
223
224 gbc.gridx = 2;
225 gbc.gridwidth = GridBagConstraints.REMAINDER;
226 gbc.gridheight = 1;
227 gbc.fill = GridBagConstraints.NONE;
228
229 dateDCPanel = new DCPanel();
230 yearDCPanel = new DCPanel();
231 hourDCPanel = new DCPanel();
232 minuteDCPanel = new DCPanel();
233 secondDCPanel = new DCPanel();
234
235 gbc.gridy = 1;
236 topPanel.add(dateDCPanel, gbc);
237
238 gbc.gridy = GridBagConstraints.RELATIVE;
239 topPanel.add(yearDCPanel, gbc);
240 topPanel.add(hourDCPanel, gbc);
241 topPanel.add(minuteDCPanel, gbc);
242 topPanel.add(secondDCPanel, gbc);
243
244 dateDCPanel.setListener(date);
245 yearDCPanel.setListener(year);
246 hourDCPanel.setListener(hour);
247 minuteDCPanel.setListener(minute);
248 secondDCPanel.setListener(second);
249
250 }
251
252
253 /**
254 * Sets the strings in the month pull-down menu. Also adds a listener
255 * that will modify the maximum date allowed depending on the month.
256 */
257 private void initializeMonth() {
258 DateFormatSymbols dfSymbols = new DateFormatSymbols();
259 String[] monthStrings = dfSymbols.getMonths();
260
261 month.removeAll();
262
263 for (int i = 0; i < monthStrings.length; i++) {
264 month.add(monthStrings[i]);
265 }
266
267 month.addItemListener(new DCMonthChangeListener());
268 }
269
270 // Adds all the buttons
271 private void addButtons() {
272
273 GridBagConstraints gbc = new GridBagConstraints();
274 gbc.weighty = 1;
275
276
277 middlePanel = new Panel();
278 now = new Button(getString("Now"));
279 midnight = new Button(getString("Midnight"));
280 middlePanel.add(midnight);
281 middlePanel.add(now);
282 gbc.fill = GridBagConstraints.HORIZONTAL;
283 gbc.gridwidth = GridBagConstraints.REMAINDER;
284 gbc.gridx = 0;
285 gbc.gridy = 1;
286 add(middlePanel, gbc);
287
288 gbc.gridwidth = GridBagConstraints.REMAINDER;
289 gbc.gridheight = 1;
290 gbc.fill = GridBagConstraints.BOTH;
291 gbc.gridx = 0;
292 gbc.gridy = 2;
293 add(new LineSeparator(), gbc);
294
295 bottomPanel = new Panel();
296 ok = new Button(getString("OK"));
297 cancel = new Button(getString("Cancel"));
298 help = new Button(getString("Help"));
299 bottomPanel.add(ok);
300 bottomPanel.add(cancel);
301 bottomPanel.add(help);
302 gbc.fill = GridBagConstraints.HORIZONTAL;
303 gbc.gridwidth = GridBagConstraints.REMAINDER;
304 gbc.gridx = 0;
305 gbc.gridy = 3;
306 add(bottomPanel, gbc);
307
308 DCButtonListener bl = new DCButtonListener();
309 ok.addActionListener(bl);
310 cancel.addActionListener(bl);
311 help.addActionListener(bl);
312 now.addActionListener(bl);
313 midnight.addActionListener(bl);
314
315 }
316
317 /**
318 * Adds a listener to all the text fields so that when they go out
319 * of focus (by tab or clicking), their values are checked for
320 * errors.
321 */
322 private void addFocusListeners() {
323 FocusListener fl = new DCFocusListener();
324 date.addFocusListener(fl);
325 year.addFocusListener(fl);
326 hour.addFocusListener(fl);
327 minute.addFocusListener(fl);
328 second.addFocusListener(fl);
329 }
330
331 /**
332 * Closes (hides) the dialog box when the user is done
333 * @param save true if the box is being dismissed by clicking on
334 * "ok" and the user wants to retain the modified value, false
335 * otherwise.
336 */
337 private void dateTimeDialogClose(boolean save) {
338 if (save == true) {
339 if (!updateFromGui())
340 return;
341 }
342 this.save = save;
343 setVisible(false);
344 }
345
346 /**
347 * Checks to see is all text fields contain valid values.
348 * @return true if all are valid, false otherwise.
349 */
350 private boolean updateFromGui() {
351 return (checkErrorAndSet(date) && checkErrorAndSet(year) &&
352 checkErrorAndSet(hour) && checkErrorAndSet(minute) &&
353 checkErrorAndSet(second));
354 }
355
356 /**
357 * Checks the value stored as text in the field and sets its numeric
358 * value to that if it is legitimate.
359 * @return true if the value was legitimate and got set, false
360 * otherwise.
361 */
362 private boolean checkErrorAndSet(DCTextField tf) {
363 int i = 0;
364 boolean errorState = false;
365 try {
366 i = new Integer(tf.getText().trim()).intValue();
367 errorState = !tf.checkValue(i);
368 } catch (NumberFormatException e2) {
369 errorState = true;
370 }
371 if (errorState) {
372 tf.selectAll();
373 toolkit.beep();
374 }
375 else
376 tf.setValue(i);
377 return !errorState;
378 }
379
380 /**
381 * Checks if the user requested that the value in this
382 * DateTimeDialog be used e.g., by clicking on "Ok" instead of
383 * "Cancel."
384 * @return true if the user wants to save the value in the
385 * DateTimeDialog, false otherwise.
386 */
387
388 public boolean isSaved() {
389 return save;
390 }
391
392 /**
393 * Sets the date and time in fields to the current date and time.
394 */
395 public void setCurrentTime() {
396 setDate(new Date());
397 }
398
399 /**
400 * Sets the current date of the DateTimeDialog and updates the gui
401 * components to reflect that.
402 * @param date the Date to set it to.
403 */
404 public void setDate(Date newDate) {
405 calendar = new GregorianCalendar();
406 calendar.setTime(newDate);
407
408 // update gui components now
409
410 year.setValue(calendar.get(Calendar.YEAR));
411 month.select(calendar.get(Calendar.MONTH));
412 date.setValue(calendar.get(Calendar.DATE));
413
414 // Make sure the date is in the valid range for the given month
415 fixDateField();
416
417 hour.setValue(calendar.get(Calendar.HOUR_OF_DAY));
418 minute.setValue(calendar.get(Calendar.MINUTE));
419 second.setValue(calendar.get(Calendar.SECOND));
420
421 }
422
423 /**
424 * Set the time fields to midnight, i.e., clears them.
425 */
426 private void setMidnight() {
427 hour.setValue(0);
428 minute.setValue(0);
429 second.setValue(0);
430 }
431
432 /**
433 * Make sure the date does not exceed the maximum allowable value
434 * for the currently selected month.
435 */
436 private void fixDateField() {
437 int monthIndex = month.getSelectedIndex();
438 int max = MONTH_LEN[monthIndex];
439 date.setMaximum(calendar.isLeapYear(year.getValue()) &&
440 monthIndex == 1 ? max + 1 : max);
441 }
442
443 // * **********************************************
444 // I N N E R C L A S S E S F O L L O W
445 // ***********************************************
446
447 /**
448 * Listener for closing the dialog box through the window close
449 * menu.
450 */
451 private class DCWindowListener extends WindowAdapter {
452 public void windowClosing(WindowEvent e) {
453 dateTimeDialogClose(false);
454 }
455 }
456
457 /**
458 * Listener for any change in the month selected through the
459 * pull down menu
460 */
461 private class DCMonthChangeListener implements ItemListener {
462 public void itemStateChanged(ItemEvent e) {
463 fixDateField();
464 }
465 }
466
467 /**
468 * Listener for all the buttons. The listener is shared for the sake
469 * of reducing the number of overall listeners.
470 * TBD: I18N the help
471 */
472 private class DCButtonListener implements ActionListener {
473 public void actionPerformed(ActionEvent e) {
474 if (e.getSource() == ok) {
475 DateTimeDialog.this.dateTimeDialogClose(true);
476 }
477 else
478 if (e.getSource() == cancel) {
479 DateTimeDialog.this.dateTimeDialogClose(false);
480 }
481 else
482 if (e.getSource() == now) {
483 DateTimeDialog.this.setCurrentTime();
484 }
485 else
486 if (e.getSource() == midnight) {
487 DateTimeDialog.this.setMidnight();
488 }
489 else
490 if (e.getSource() == help) {
491 if (hd != null)
492 hd.setVisible(true);
493 else {
494 hd = new
495 HelpDialog(DateTimeDialog.this.parent,
496 getString("Help for Date and Time Dialog"), false);
497 hd.setVisible(true);
498 hd.setText(getString(hrb, "DateTimeDialogHelp"));
499 }
500 }
501 } // actionPerformed
502 }
503
504 /**
505 * Listener for any change in focus with respect to the text
506 * fields. When a text field is going out of focus, it detemines if the
507 * text value in it is valid. If not, it returns focus to that text
508 * field.
509 */
510 private class DCFocusListener extends FocusAdapter {
511
512 public void focusLost(FocusEvent e) {
513 if (!checkErrorAndSet((DCTextField)e.getSource()))
514 ((DCTextField)e.getSource()).requestFocus();
515 }
516 }
517
518 /**
519 * The string representation of the dialog box.
520 * @return a String which contians the date and time in locale
521 * default format, but to MEDIUM length formatting style.
522 */
523 public String toString() {
524 calendar = new GregorianCalendar(year.getValue(),
525 month.getSelectedIndex(),
526 date.getValue(),
527 hour.getValue(),
528 minute.getValue(),
529 second.getValue());
530 return df.format(calendar.getTime());
531 }
532
533 /**
534 * Call rb.getString(), but catch exception and return English
535 * key so that small spelling errors don't cripple the GUI
536 *
537 */
538 private static final String getString(String key) {
539 return (getString(rb, key));
540 }
541
542 private static final String getString(ResourceBundle rb, String key) {
543 try {
544 String res = rb.getString(key);
545 return res;
546 } catch (MissingResourceException e) {
547 System.out.println("Missing resource "+key+", using English.");
548 return key;
549 }
550 }
551
552 /* BEGIN JSTYLED */
553 /*
554 public static final void main(String args[]) {
555 Frame f = new Frame();
556 // while (true){
557 DateTimeDialog d = new DateTimeDialog(f, Color.white, Color.black);
558 d.setVisible(true);
559 System.out.println(d.toString());
560 // }
561 }
562 */
563 /* END JSTYLED */
564 }