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.show(); 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 } 565