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 } 565