001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas/ 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see https://www.gnu.org/licenses/. 027 */ 028 029package edu.wisc.ssec.mcidasv.data.dateChooser; 030 031import java.awt.BorderLayout; 032import java.awt.Color; 033import java.awt.Font; 034import java.beans.PropertyChangeEvent; 035import java.beans.PropertyChangeListener; 036import java.util.Calendar; 037import java.util.Date; 038import java.util.Locale; 039 040import javax.swing.BorderFactory; 041import javax.swing.JFrame; 042import javax.swing.JPanel; 043 044/** 045 * JCalendar is a bean for entering a date by choosing the year, month and day. 046 * 047 * @author Kai Toedter 048 * @version $LastChangedRevision: 95 $ 049 * @version $LastChangedDate: 2006-05-05 18:43:15 +0200 (Fr, 05 Mai 2006) $ 050 */ 051public class JCalendar extends JPanel implements PropertyChangeListener { 052 private static final long serialVersionUID = 8913369762644440133L; 053 054 private Calendar calendar; 055 056 /** the day chooser */ 057 protected JDayChooser dayChooser; 058 private boolean initialized = false; 059 060 /** indicates if weeks of year shall be visible */ 061 protected boolean weekOfYearVisible = true; 062 063 /** the locale */ 064 protected Locale locale; 065 066 /** the month chooser */ 067 protected JMonthChooser monthChooser; 068 069 private JPanel monthYearPanel; 070 071 /** the year chhoser */ 072 protected JYearChooser yearChooser; 073 074 protected Date minSelectableDate; 075 076 protected Date maxSelectableDate; 077 078 /** 079 * Default JCalendar constructor. 080 */ 081 public JCalendar() { 082 this(null, null, true, true); 083 } 084 085 /** 086 * JCalendar constructor which allows the initial date to be set. 087 * 088 * @param date 089 * the date 090 */ 091 public JCalendar(Date date) { 092 this(date, null, true, true); 093 } 094 095 /** 096 * JCalendar constructor which allows the initial calendar to be set. 097 * 098 * @param calendar 099 * the calendar 100 */ 101 public JCalendar(Calendar calendar) { 102 this(null, null, true, true); 103 setCalendar(calendar); 104 } 105 106 /** 107 * JCalendar constructor allowing the initial locale to be set. 108 * 109 * @param locale 110 * the new locale 111 */ 112 public JCalendar(Locale locale) { 113 this(null, locale, true, true); 114 } 115 116 /** 117 * JCalendar constructor specifying both the initial date and locale. 118 * 119 * @param date 120 * the date 121 * @param locale 122 * the new locale 123 */ 124 public JCalendar(Date date, Locale locale) { 125 this(date, locale, true, true); 126 } 127 128 /** 129 * JCalendar constructor specifying both the initial date and the month 130 * spinner type. 131 * 132 * @param date 133 * the date 134 * @param monthSpinner 135 * false, if no month spinner should be used 136 */ 137 public JCalendar(Date date, boolean monthSpinner) { 138 this(date, null, monthSpinner, true); 139 } 140 141 /** 142 * JCalendar constructor specifying both the locale and the month spinner. 143 * 144 * @param locale 145 * the locale 146 * @param monthSpinner 147 * false, if no month spinner should be used 148 */ 149 public JCalendar(Locale locale, boolean monthSpinner) { 150 this(null, locale, monthSpinner, true); 151 } 152 153 /** 154 * JCalendar constructor specifying the month spinner type. 155 * 156 * @param monthSpinner 157 * false, if no month spinner should be used 158 */ 159 public JCalendar(boolean monthSpinner) { 160 this(null, null, monthSpinner, true); 161 } 162 163 /** 164 * JCalendar constructor with month spinner parameter. 165 * 166 * @param date 167 * the date 168 * @param locale 169 * the locale 170 * @param monthSpinner 171 * false, if no month spinner should be used 172 * @param weekOfYearVisible 173 * true, if weeks of year shall be visible 174 */ 175 public JCalendar(Date date, Locale locale, boolean monthSpinner, boolean weekOfYearVisible) { 176 177 setName("JCalendar"); 178 179 // needed for setFont() etc. 180 dayChooser = null; 181 monthChooser = null; 182 yearChooser = null; 183 this.weekOfYearVisible = weekOfYearVisible; 184 185 this.locale = locale; 186 187 if (locale == null) { 188 this.locale = Locale.getDefault(); 189 } 190 191 calendar = Calendar.getInstance(); 192 193 setLayout(new BorderLayout()); 194 195 monthYearPanel = new JPanel(); 196 monthYearPanel.setLayout(new BorderLayout()); 197 198 monthChooser = new JMonthChooser(monthSpinner); 199 yearChooser = new JYearChooser(); 200 monthChooser.setYearChooser(yearChooser); 201 monthYearPanel.add(monthChooser, BorderLayout.WEST); 202 monthYearPanel.add(yearChooser, BorderLayout.CENTER); 203 monthYearPanel.setBorder(BorderFactory.createEmptyBorder()); 204 205 dayChooser = new JDayChooser(weekOfYearVisible); 206 dayChooser.addPropertyChangeListener(this); 207 monthChooser.setDayChooser(dayChooser); 208 monthChooser.addPropertyChangeListener(this); 209 yearChooser.setDayChooser(dayChooser); 210 yearChooser.addPropertyChangeListener(this); 211 add(monthYearPanel, BorderLayout.NORTH); 212 add(dayChooser, BorderLayout.CENTER); 213 214 // Set the initialized flag before setting the calendar. This will 215 // cause the other components to be updated properly. 216 if (date != null) { 217 calendar.setTime(date); 218 } 219 220 initialized = true; 221 222 setCalendar(calendar); 223 } 224 225 /** 226 * Creates a JFrame with a JCalendar inside and can be used for testing. 227 * 228 * @param s 229 * The command line arguments 230 */ 231 public static void main(String[] s) { 232 JFrame frame = new JFrame("JCalendar"); 233 234 JCalendar jcalendar = new JCalendar(); 235 frame.getContentPane().add(jcalendar); 236 frame.pack(); 237 frame.setVisible(true); 238 } 239 240 /** 241 * Returns the calendar property. 242 * 243 * @return the value of the calendar property. 244 */ 245 public Calendar getCalendar() { 246 return calendar; 247 } 248 249 /** 250 * Gets the dayChooser attribute of the JCalendar object 251 * 252 * @return the dayChooser value 253 */ 254 public JDayChooser getDayChooser() { 255 return dayChooser; 256 } 257 258 /** 259 * Returns the locale. 260 * 261 * @return the value of the locale property. 262 * 263 * @see #setLocale 264 */ 265 public Locale getLocale() { 266 return locale; 267 } 268 269 /** 270 * Gets the monthChooser attribute of the JCalendar object 271 * 272 * @return the monthChooser value 273 */ 274 public JMonthChooser getMonthChooser() { 275 return monthChooser; 276 } 277 278 /** 279 * Gets the yearChooser attribute of the JCalendar object 280 * 281 * @return the yearChooser value 282 */ 283 public JYearChooser getYearChooser() { 284 return yearChooser; 285 } 286 287 /** 288 * Indicates if the weeks of year are visible.. 289 * 290 * @return boolean true, if weeks of year are visible 291 */ 292 public boolean isWeekOfYearVisible() { 293 return dayChooser.isWeekOfYearVisible(); 294 } 295 296 /** 297 * JCalendar is a PropertyChangeListener, for its day, month and year 298 * chooser. 299 * 300 * @param evt 301 * the property change event 302 */ 303 public void propertyChange(PropertyChangeEvent evt) { 304 if (calendar != null) { 305 Calendar c = (Calendar) calendar.clone(); 306 307 if (evt.getPropertyName().equals("day")) { 308 c.set(Calendar.DAY_OF_MONTH, ((Integer) evt.getNewValue()).intValue()); 309 setCalendar(c, false); 310 } else if (evt.getPropertyName().equals("month")) { 311 c.set(Calendar.MONTH, ((Integer) evt.getNewValue()).intValue()); 312 setCalendar(c, false); 313 } else if (evt.getPropertyName().equals("year")) { 314 c.set(Calendar.YEAR, ((Integer) evt.getNewValue()).intValue()); 315 setCalendar(c, false); 316 } else if (evt.getPropertyName().equals("date")) { 317 c.setTime((Date) evt.getNewValue()); 318 setCalendar(c, true); 319 } 320 } 321 } 322 323 /** 324 * Sets the background color. 325 * 326 * @param bg 327 * the new background 328 */ 329 public void setBackground(Color bg) { 330 super.setBackground(bg); 331 332 if (dayChooser != null) { 333 dayChooser.setBackground(bg); 334 } 335 } 336 337 /** 338 * Sets the calendar property. This is a bound property. 339 * 340 * @param c 341 * the new calendar 342 * @throws NullPointerException - 343 * if c is null; 344 * @see #getCalendar 345 */ 346 public void setCalendar(Calendar c) { 347 setCalendar(c, true); 348 } 349 350 /** 351 * Sets the calendar attribute of the JCalendar object 352 * 353 * @param c 354 * the new calendar value 355 * @param update 356 * the new calendar value 357 * @throws NullPointerException - 358 * if c is null; 359 */ 360 private void setCalendar(Calendar c, boolean update) { 361 if (c == null) { 362 setDate(null); 363 } 364 Calendar oldCalendar = calendar; 365 calendar = c; 366 367 if (update) { 368 // Thanks to Jeff Ulmer for correcting a bug in the sequence :) 369 yearChooser.setYear(c.get(Calendar.YEAR)); 370 monthChooser.setMonth(c.get(Calendar.MONTH)); 371 dayChooser.setDay(c.get(Calendar.DATE)); 372 } 373 374 firePropertyChange("calendar", oldCalendar, calendar); 375 } 376 377 /** 378 * Enable or disable the JCalendar. 379 * 380 * @param enabled 381 * the new enabled value 382 */ 383 public void setEnabled(boolean enabled) { 384 super.setEnabled(enabled); 385 386 if (dayChooser != null) { 387 dayChooser.setEnabled(enabled); 388 monthChooser.setEnabled(enabled); 389 yearChooser.setEnabled(enabled); 390 } 391 } 392 393 /** 394 * Returns true, if enabled. 395 * 396 * @return true, if enabled. 397 */ 398 public boolean isEnabled() { 399 return super.isEnabled(); 400 } 401 402 /** 403 * Sets the font property. 404 * 405 * @param font 406 * the new font 407 */ 408 public void setFont(Font font) { 409 super.setFont(font); 410 411 if (dayChooser != null) { 412 dayChooser.setFont(font); 413 monthChooser.setFont(font); 414 yearChooser.setFont(font); 415 } 416 } 417 418 /** 419 * Sets the foreground color. 420 * 421 * @param fg 422 * the new foreground 423 */ 424 public void setForeground(Color fg) { 425 super.setForeground(fg); 426 427 if (dayChooser != null) { 428 dayChooser.setForeground(fg); 429 monthChooser.setForeground(fg); 430 yearChooser.setForeground(fg); 431 } 432 } 433 434 /** 435 * Sets the locale property. This is a bound property. 436 * 437 * @param l 438 * the new locale value 439 * 440 * @see #getLocale 441 */ 442 public void setLocale(Locale l) { 443 if (!initialized) { 444 super.setLocale(l); 445 } else { 446 Locale oldLocale = locale; 447 locale = l; 448 dayChooser.setLocale(locale); 449 monthChooser.setLocale(locale); 450 firePropertyChange("locale", oldLocale, locale); 451 } 452 } 453 454 /** 455 * Sets the week of year visible. 456 * 457 * @param weekOfYearVisible 458 * true, if weeks of year shall be visible 459 */ 460 public void setWeekOfYearVisible(boolean weekOfYearVisible) { 461 dayChooser.setWeekOfYearVisible(weekOfYearVisible); 462 setLocale(locale); // hack for doing complete new layout :) 463 } 464 465 /** 466 * Gets the visibility of the decoration background. 467 * 468 * @return true, if the decoration background is visible. 469 */ 470 public boolean isDecorationBackgroundVisible() { 471 return dayChooser.isDecorationBackgroundVisible(); 472 } 473 474 /** 475 * Sets the decoration background visible. 476 * 477 * @param decorationBackgroundVisible 478 * true, if the decoration background should be visible. 479 */ 480 public void setDecorationBackgroundVisible(boolean decorationBackgroundVisible) { 481 dayChooser.setDecorationBackgroundVisible(decorationBackgroundVisible); 482 setLocale(locale); // hack for doing complete new layout :) 483 } 484 485 /** 486 * Gets the visibility of the decoration border. 487 * 488 * @return true, if the decoration border is visible. 489 */ 490 public boolean isDecorationBordersVisible() { 491 return dayChooser.isDecorationBordersVisible(); 492 } 493 494 /** 495 * Sets the decoration borders visible. 496 * 497 * @param decorationBordersVisible 498 * true, if the decoration borders should be visible. 499 */ 500 public void setDecorationBordersVisible(boolean decorationBordersVisible) { 501 dayChooser.setDecorationBordersVisible(decorationBordersVisible); 502 setLocale(locale); // hack for doing complete new layout :) 503 } 504 505 /** 506 * Returns the color of the decoration (day names and weeks). 507 * 508 * @return the color of the decoration (day names and weeks). 509 */ 510 public Color getDecorationBackgroundColor() { 511 return dayChooser.getDecorationBackgroundColor(); 512 } 513 514 /** 515 * Sets the background of days and weeks of year buttons. 516 * 517 * @param decorationBackgroundColor 518 * the background color 519 */ 520 public void setDecorationBackgroundColor(Color decorationBackgroundColor) { 521 dayChooser.setDecorationBackgroundColor(decorationBackgroundColor); 522 } 523 524 /** 525 * Returns the Sunday foreground. 526 * 527 * @return Color the Sunday foreground. 528 */ 529 public Color getSundayForeground() { 530 return dayChooser.getSundayForeground(); 531 } 532 533 /** 534 * Returns the weekday foreground. 535 * 536 * @return Color the weekday foreground. 537 */ 538 public Color getWeekdayForeground() { 539 return dayChooser.getWeekdayForeground(); 540 } 541 542 /** 543 * Sets the Sunday foreground. 544 * 545 * @param sundayForeground 546 * the sundayForeground to set 547 */ 548 public void setSundayForeground(Color sundayForeground) { 549 dayChooser.setSundayForeground(sundayForeground); 550 } 551 552 /** 553 * Sets the weekday foreground. 554 * 555 * @param weekdayForeground 556 * the weekdayForeground to set 557 */ 558 public void setWeekdayForeground(Color weekdayForeground) { 559 dayChooser.setWeekdayForeground(weekdayForeground); 560 } 561 562 /** 563 * Returns a Date object. 564 * 565 * @return a date object constructed from the calendar property. 566 */ 567 public Date getDate() { 568 return new Date(calendar.getTimeInMillis()); 569 } 570 571 /** 572 * Sets the date. Fires the property change "date". 573 * 574 * @param date 575 * the new date. 576 * @throws NullPointerException - 577 * if tha date is null 578 */ 579 public void setDate(Date date) { 580 Date oldDate = calendar.getTime(); 581 calendar.setTime(date); 582 int year = calendar.get(Calendar.YEAR); 583 int month = calendar.get(Calendar.MONTH); 584 int day = calendar.get(Calendar.DAY_OF_MONTH); 585 586 yearChooser.setYear(year); 587 monthChooser.setMonth(month); 588 dayChooser.setCalendar(calendar); 589 dayChooser.setDay(day); 590 591 firePropertyChange("date", oldDate, date); 592 } 593 594 /** 595 * Sets a valid date range for selectable dates. If max is before 596 * min, the default range with no limitation is set. 597 * 598 * @param min 599 * the minimum selectable date or null (then the minimum date is 600 * set to 01\01\0001) 601 * @param max 602 * the maximum selectable date or null (then the maximum date is 603 * set to 01\01\9999) 604 */ 605 public void setSelectableDateRange(Date min, Date max) { 606 dayChooser.setSelectableDateRange(min, max); 607 }; 608 609 /** 610 * Gets the minimum selectable date. 611 * 612 * @return the minimum selectable date 613 */ 614 public Date getMaxSelectableDate() { 615 return dayChooser.getMaxSelectableDate(); 616 } 617 618 /** 619 * Gets the maximum selectable date. 620 * 621 * @return the maximum selectable date 622 */ 623 public Date getMinSelectableDate() { 624 return dayChooser.getMinSelectableDate(); 625 } 626 627 /** 628 * Sets the maximum selectable date. 629 * 630 * @param max maximum selectable date 631 */ 632 public void setMaxSelectableDate(Date max) { 633 dayChooser.setMaxSelectableDate(max); 634 } 635 636 /** 637 * Sets the minimum selectable date. 638 * 639 * @param min minimum selectable date 640 */ 641 public void setMinSelectableDate(Date min) { 642 dayChooser.setMinSelectableDate(min); 643 } 644 645 /** 646 * Gets the maximum number of characters of a day name or 0. If 0 is 647 * returned, dateFormatSymbols.getShortWeekdays() will be used. 648 * 649 * @return the maximum number of characters of a day name or 0. 650 */ 651 public int getMaxDayCharacters() { 652 return dayChooser.getMaxDayCharacters(); 653 } 654 655 /** 656 * Sets the maximum number of characters per day in the day bar. Valid 657 * values are 0-4. If set to 0, dateFormatSymbols.getShortWeekdays() will be 658 * used, otherwise theses strings will be reduced to the maximum number of 659 * characters. 660 * 661 * @param maxDayCharacters 662 * the maximum number of characters of a day name. 663 */ 664 public void setMaxDayCharacters(int maxDayCharacters) { 665 dayChooser.setMaxDayCharacters(maxDayCharacters); 666 } 667}