001 /*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2013
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 http://www.gnu.org/licenses.
027 */
028
029 package edu.wisc.ssec.mcidasv.data.dateChooser;
030
031 import java.awt.BorderLayout;
032 import java.awt.Color;
033 import java.awt.Font;
034 import java.beans.PropertyChangeEvent;
035 import java.beans.PropertyChangeListener;
036 import java.util.Calendar;
037 import java.util.Date;
038 import java.util.Locale;
039
040 import javax.swing.BorderFactory;
041 import javax.swing.JFrame;
042 import 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 */
051 public 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 }