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