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