001 /*
002 * $Id: JDayChooser.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 package edu.wisc.ssec.mcidasv.data.dateChooser;
031
032 import java.awt.BorderLayout;
033 import java.awt.Color;
034 import java.awt.Font;
035 import java.awt.Graphics;
036 import java.awt.GridLayout;
037 import java.awt.Insets;
038 import java.awt.event.ActionEvent;
039 import java.awt.event.ActionListener;
040 import java.awt.event.FocusEvent;
041 import java.awt.event.FocusListener;
042 import java.awt.event.KeyEvent;
043 import java.awt.event.KeyListener;
044 import java.awt.event.MouseListener;
045
046 import java.text.DateFormatSymbols;
047
048 import java.util.Calendar;
049 import java.util.Date;
050 import java.util.Locale;
051
052 import javax.swing.JButton;
053 import javax.swing.JFrame;
054 import javax.swing.JPanel;
055 import javax.swing.UIManager;
056
057 /**
058 * JDayChooser is a bean for choosing a day.
059 *
060 * @author Kai Toedter
061 * @version $LastChangedRevision: 107 $
062 * @version $LastChangedDate: 2009-05-01 15:48:00 +0200 (Fr, 01 Mai 2009) $
063 */
064 public class JDayChooser extends JPanel implements ActionListener, KeyListener,
065 FocusListener {
066 private static final long serialVersionUID = 5876398337018781820L;
067
068 protected JButton[] days;
069
070 protected JButton[] weeks;
071
072 protected JButton selectedDay;
073
074 protected JPanel weekPanel;
075
076 protected JPanel dayPanel;
077
078 protected int day;
079
080 protected Color oldDayBackgroundColor;
081
082 protected Color selectedColor;
083
084 protected Color sundayForeground;
085
086 protected Color weekdayForeground;
087
088 protected Color decorationBackgroundColor;
089
090 protected String[] dayNames;
091
092 protected Calendar calendar;
093
094 protected Calendar today;
095
096 protected Locale locale;
097
098 protected boolean initialized;
099
100 protected boolean weekOfYearVisible;
101
102 protected boolean decorationBackgroundVisible = true;
103
104 protected boolean decorationBordersVisible;
105
106 protected boolean dayBordersVisible;
107
108 private boolean alwaysFireDayProperty;
109
110 protected Date minSelectableDate;
111
112 protected Date maxSelectableDate;
113
114 protected Date defaultMinSelectableDate;
115
116 protected Date defaultMaxSelectableDate;
117
118 protected int maxDayCharacters;
119
120 /**
121 * Default JDayChooser constructor.
122 */
123 public JDayChooser() {
124 this(false);
125 }
126
127 /**
128 * JDayChooser constructor.
129 *
130 * @param weekOfYearVisible
131 * true, if the weeks of a year shall be shown
132 */
133 public JDayChooser(boolean weekOfYearVisible) {
134 setName("JDayChooser");
135 setBackground(Color.blue);
136 this.weekOfYearVisible = weekOfYearVisible;
137 locale = Locale.getDefault();
138 days = new JButton[49];
139 selectedDay = null;
140 calendar = Calendar.getInstance(locale);
141 today = (Calendar) calendar.clone();
142
143 setLayout(new BorderLayout());
144
145 dayPanel = new JPanel();
146 dayPanel.setLayout(new GridLayout(7, 7));
147
148 sundayForeground = new Color(164, 0, 0);
149 weekdayForeground = new Color(0, 90, 164);
150
151 // decorationBackgroundColor = new Color(194, 211, 252);
152 // decorationBackgroundColor = new Color(206, 219, 246);
153 decorationBackgroundColor = new Color(210, 228, 238);
154
155 for (int y = 0; y < 7; y++) {
156 for (int x = 0; x < 7; x++) {
157 int index = x + (7 * y);
158
159 if (y == 0) {
160 // Create a button that doesn't react on clicks or focus
161 // changes.
162 // Thanks to Thomas Schaefer for the focus hint :)
163 days[index] = new DecoratorButton();
164 } else {
165 days[index] = new JButton("x") {
166 private static final long serialVersionUID = -7433645992591669725L;
167
168 public void paint(Graphics g) {
169 if ("Windows".equals(UIManager.getLookAndFeel()
170 .getID())) {
171 // this is a hack to get the background painted
172 // when using Windows Look & Feel
173 if (selectedDay == this) {
174 g.setColor(selectedColor);
175 g.fillRect(0, 0, getWidth(), getHeight());
176 }
177 }
178 super.paint(g);
179 }
180
181 };
182 days[index].addActionListener(this);
183 days[index].addKeyListener(this);
184 days[index].addFocusListener(this);
185 }
186
187 days[index].setMargin(new Insets(0, 0, 0, 0));
188 days[index].setFocusPainted(false);
189 dayPanel.add(days[index]);
190 }
191 }
192
193 weekPanel = new JPanel();
194 weekPanel.setLayout(new GridLayout(7, 1));
195 weeks = new JButton[7];
196
197 for (int i = 0; i < 7; i++) {
198 weeks[i] = new DecoratorButton();
199 weeks[i].setMargin(new Insets(0, 0, 0, 0));
200 weeks[i].setFocusPainted(false);
201 weeks[i].setForeground(new Color(100, 100, 100));
202
203 if (i != 0) {
204 weeks[i].setText("0" + (i + 1));
205 }
206
207 weekPanel.add(weeks[i]);
208 }
209
210 Calendar tmpCalendar = Calendar.getInstance();
211 tmpCalendar.set(1, 0, 1, 1, 1);
212 defaultMinSelectableDate = tmpCalendar.getTime();
213 minSelectableDate = defaultMinSelectableDate;
214 tmpCalendar.set(9999, 0, 1, 1, 1);
215 defaultMaxSelectableDate = tmpCalendar.getTime();
216 maxSelectableDate = defaultMaxSelectableDate;
217
218 init();
219
220 setDay(Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
221 add(dayPanel, BorderLayout.CENTER);
222
223 if (weekOfYearVisible) {
224 add(weekPanel, BorderLayout.WEST);
225 }
226 initialized = true;
227 updateUI();
228 }
229
230 /**
231 * Initilizes the locale specific names for the days of the week.
232 */
233 protected void init() {
234 JButton testButton = new JButton();
235 oldDayBackgroundColor = testButton.getBackground();
236 selectedColor = new Color(160, 160, 160);
237
238 Date date = calendar.getTime();
239 calendar = Calendar.getInstance(locale);
240 calendar.setTime(date);
241
242 drawDayNames();
243 drawDays();
244 }
245
246 /**
247 * Draws the day names of the day columnes.
248 */
249 private void drawDayNames() {
250 int firstDayOfWeek = calendar.getFirstDayOfWeek();
251 DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(locale);
252 dayNames = dateFormatSymbols.getShortWeekdays();
253
254 int day = firstDayOfWeek;
255
256 for (int i = 0; i < 7; i++) {
257 if (maxDayCharacters > 0 && maxDayCharacters < 5) {
258 if (dayNames[day].length() >= maxDayCharacters) {
259 dayNames[day] = dayNames[day]
260 .substring(0, maxDayCharacters);
261 }
262 }
263
264 days[i].setText(dayNames[day]);
265
266 if (day == 1) {
267 days[i].setForeground(sundayForeground);
268 } else {
269 days[i].setForeground(weekdayForeground);
270 }
271
272 if (day < 7) {
273 day++;
274 } else {
275 day -= 6;
276 }
277 }
278 }
279
280 /**
281 * Initializes both day names and weeks of the year.
282 */
283 protected void initDecorations() {
284 for (int x = 0; x < 7; x++) {
285 days[x].setContentAreaFilled(decorationBackgroundVisible);
286 days[x].setBorderPainted(decorationBordersVisible);
287 days[x].invalidate();
288 days[x].repaint();
289 weeks[x].setContentAreaFilled(decorationBackgroundVisible);
290 weeks[x].setBorderPainted(decorationBordersVisible);
291 weeks[x].invalidate();
292 weeks[x].repaint();
293 }
294 }
295
296 /**
297 * Hides and shows the week buttons.
298 */
299 protected void drawWeeks() {
300 Calendar tmpCalendar = (Calendar) calendar.clone();
301
302 for (int i = 1; i < 7; i++) {
303 tmpCalendar.set(Calendar.DAY_OF_MONTH, (i * 7) - 6);
304
305 int week = tmpCalendar.get(Calendar.WEEK_OF_YEAR);
306 String buttonText = Integer.toString(week);
307
308 if (week < 10) {
309 buttonText = "0" + buttonText;
310 }
311
312 weeks[i].setText(buttonText);
313
314 if ((i == 5) || (i == 6)) {
315 weeks[i].setVisible(days[i * 7].isVisible());
316 }
317 }
318 }
319
320 /**
321 * Hides and shows the day buttons.
322 */
323 protected void drawDays() {
324 Calendar tmpCalendar = (Calendar) calendar.clone();
325 tmpCalendar.set(Calendar.HOUR_OF_DAY, 0);
326 tmpCalendar.set(Calendar.MINUTE, 0);
327 tmpCalendar.set(Calendar.SECOND, 0);
328 tmpCalendar.set(Calendar.MILLISECOND, 0);
329
330 Calendar minCal = Calendar.getInstance();
331 minCal.setTime(minSelectableDate);
332 minCal.set(Calendar.HOUR_OF_DAY, 0);
333 minCal.set(Calendar.MINUTE, 0);
334 minCal.set(Calendar.SECOND, 0);
335 minCal.set(Calendar.MILLISECOND, 0);
336
337 Calendar maxCal = Calendar.getInstance();
338 maxCal.setTime(maxSelectableDate);
339 maxCal.set(Calendar.HOUR_OF_DAY, 0);
340 maxCal.set(Calendar.MINUTE, 0);
341 maxCal.set(Calendar.SECOND, 0);
342 maxCal.set(Calendar.MILLISECOND, 0);
343
344 int firstDayOfWeek = tmpCalendar.getFirstDayOfWeek();
345 tmpCalendar.set(Calendar.DAY_OF_MONTH, 1);
346
347 int firstDay = tmpCalendar.get(Calendar.DAY_OF_WEEK) - firstDayOfWeek;
348
349 if (firstDay < 0) {
350 firstDay += 7;
351 }
352
353 int i;
354
355 for (i = 0; i < firstDay; i++) {
356 days[i + 7].setVisible(false);
357 days[i + 7].setText("");
358 }
359
360 tmpCalendar.add(Calendar.MONTH, 1);
361
362 Date firstDayInNextMonth = tmpCalendar.getTime();
363 tmpCalendar.add(Calendar.MONTH, -1);
364
365 Date day = tmpCalendar.getTime();
366 int n = 0;
367 Color foregroundColor = getForeground();
368
369 while (day.before(firstDayInNextMonth)) {
370 days[i + n + 7].setText(Integer.toString(n + 1));
371 days[i + n + 7].setVisible(true);
372
373 if ((tmpCalendar.get(Calendar.DAY_OF_YEAR) == today
374 .get(Calendar.DAY_OF_YEAR))
375 && (tmpCalendar.get(Calendar.YEAR) == today
376 .get(Calendar.YEAR))) {
377 days[i + n + 7].setForeground(sundayForeground);
378 } else {
379 days[i + n + 7].setForeground(foregroundColor);
380 }
381
382 if ((n + 1) == this.day) {
383 days[i + n + 7].setBackground(selectedColor);
384 selectedDay = days[i + n + 7];
385 } else {
386 days[i + n + 7].setBackground(oldDayBackgroundColor);
387 }
388
389 if (tmpCalendar.before(minCal) || tmpCalendar.after(maxCal)) {
390 days[i + n + 7].setEnabled(false);
391 } else {
392 days[i + n + 7].setEnabled(true);
393 }
394
395 n++;
396 tmpCalendar.add(Calendar.DATE, 1);
397 day = tmpCalendar.getTime();
398 }
399
400 for (int k = n + i + 7; k < 49; k++) {
401 days[k].setVisible(false);
402 days[k].setText("");
403 }
404
405 drawWeeks();
406 }
407
408 /**
409 * Returns the locale.
410 *
411 * @return the locale value
412 *
413 * @see #setLocale
414 */
415 public Locale getLocale() {
416 return locale;
417 }
418
419 /**
420 * Sets the locale.
421 *
422 * @param locale
423 * the new locale value
424 *
425 * @see #getLocale
426 */
427 public void setLocale(Locale locale) {
428 if (!initialized) {
429 super.setLocale(locale);
430 } else {
431 this.locale = locale;
432 super.setLocale(locale);
433 init();
434 }
435 }
436
437 /**
438 * Sets the day. This is a bound property.
439 *
440 * @param d
441 * the day
442 *
443 * @see #getDay
444 */
445 public void setDay(int d) {
446 if (d < 1) {
447 d = 1;
448 }
449 Calendar tmpCalendar = (Calendar) calendar.clone();
450 tmpCalendar.set(Calendar.DAY_OF_MONTH, 1);
451 tmpCalendar.add(Calendar.MONTH, 1);
452 tmpCalendar.add(Calendar.DATE, -1);
453
454 int maxDaysInMonth = tmpCalendar.get(Calendar.DATE);
455
456 if (d > maxDaysInMonth) {
457 d = maxDaysInMonth;
458 }
459
460 int oldDay = day;
461 day = d;
462
463 if (selectedDay != null) {
464 selectedDay.setBackground(oldDayBackgroundColor);
465 selectedDay.repaint();
466 }
467
468 for (int i = 7; i < 49; i++) {
469 if (days[i].getText().equals(Integer.toString(day))) {
470 selectedDay = days[i];
471 selectedDay.setBackground(selectedColor);
472 break;
473 }
474 }
475
476 if (alwaysFireDayProperty) {
477 firePropertyChange("day", 0, day);
478 } else {
479 firePropertyChange("day", oldDay, day);
480 }
481 }
482
483 /**
484 * this is needed for JDateChooser.
485 *
486 * @param alwaysFire
487 * true, if day property shall be fired every time a day is
488 * chosen.
489 */
490 public void setAlwaysFireDayProperty(boolean alwaysFire) {
491 alwaysFireDayProperty = alwaysFire;
492 }
493
494 /**
495 * Returns the selected day.
496 *
497 * @return the day value
498 *
499 * @see #setDay
500 */
501 public int getDay() {
502 return day;
503 }
504
505 /**
506 * Sets a specific month. This is needed for correct graphical
507 * representation of the days.
508 *
509 * @param month
510 * the new month
511 */
512 public void setMonth(int month) {
513 calendar.set(Calendar.MONTH, month);
514 int maxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
515
516 int adjustedDay = day;
517 if (day > maxDays) {
518 adjustedDay = maxDays;
519 setDay(adjustedDay);
520 }
521
522 drawDays();
523 }
524
525 /**
526 * Sets a specific year. This is needed for correct graphical representation
527 * of the days.
528 *
529 * @param year
530 * the new year
531 */
532 public void setYear(int year) {
533 calendar.set(Calendar.YEAR, year);
534 drawDays();
535 }
536
537 /**
538 * Sets a specific calendar. This is needed for correct graphical
539 * representation of the days.
540 *
541 * @param calendar
542 * the new calendar
543 */
544 public void setCalendar(Calendar calendar) {
545 this.calendar = calendar;
546 drawDays();
547 }
548
549 /**
550 * Sets the font property.
551 *
552 * @param font
553 * the new font
554 */
555 public void setFont(Font font) {
556 if (days != null) {
557 for (int i = 0; i < 49; i++) {
558 days[i].setFont(font);
559 }
560 }
561 if (weeks != null) {
562 for (int i = 0; i < 7; i++) {
563 weeks[i].setFont(font);
564 }
565 }
566 }
567
568 /**
569 * Sets the foregroundColor color.
570 *
571 * @param foreground
572 * the new foregroundColor
573 */
574 public void setForeground(Color foreground) {
575 super.setForeground(foreground);
576
577 if (days != null) {
578 for (int i = 7; i < 49; i++) {
579 days[i].setForeground(foreground);
580 }
581
582 drawDays();
583 }
584 }
585
586 /**
587 * JDayChooser is the ActionListener for all day buttons.
588 *
589 * @param e
590 * the ActionEvent
591 */
592 public void actionPerformed(ActionEvent e) {
593 JButton button = (JButton) e.getSource();
594 String buttonText = button.getText();
595 int day = new Integer(buttonText).intValue();
596 setDay(day);
597 }
598
599 /**
600 * JDayChooser is the FocusListener for all day buttons. (Added by Thomas
601 * Schaefer)
602 *
603 * @param e
604 * the FocusEvent
605 */
606 /*
607 * Code below commented out by Mark Brown on 24 Aug 2004. This code breaks
608 * the JDateChooser code by triggering the actionPerformed method on the
609 * next day button. This causes the date chosen to always be incremented by
610 * one day.
611 */
612 public void focusGained(FocusEvent e) {
613 // JButton button = (JButton) e.getSource();
614 // String buttonText = button.getText();
615 //
616 // if ((buttonText != null) && !buttonText.equals("") &&
617 // !e.isTemporary()) {
618 // actionPerformed(new ActionEvent(e.getSource(), 0, null));
619 // }
620 }
621
622 /**
623 * Does nothing.
624 *
625 * @param e
626 * the FocusEvent
627 */
628 public void focusLost(FocusEvent e) {
629 }
630
631 /**
632 * JDayChooser is the KeyListener for all day buttons. (Added by Thomas
633 * Schaefer and modified by Austin Moore)
634 *
635 * @param e
636 * the KeyEvent
637 */
638 public void keyPressed(KeyEvent e) {
639 int offset = (e.getKeyCode() == KeyEvent.VK_UP) ? (-7) : ((e
640 .getKeyCode() == KeyEvent.VK_DOWN) ? (+7)
641 : ((e.getKeyCode() == KeyEvent.VK_LEFT) ? (-1) : ((e
642 .getKeyCode() == KeyEvent.VK_RIGHT) ? (+1) : 0)));
643
644 int newDay = getDay() + offset;
645
646 if ((newDay >= 1)
647 && (newDay <= calendar.getMaximum(Calendar.DAY_OF_MONTH))) {
648 setDay(newDay);
649 }
650 }
651
652 /**
653 * Does nothing.
654 *
655 * @param e
656 * the KeyEvent
657 */
658 public void keyTyped(KeyEvent e) {
659 }
660
661 /**
662 * Does nothing.
663 *
664 * @param e
665 * the KeyEvent
666 */
667 public void keyReleased(KeyEvent e) {
668 }
669
670 /**
671 * Enable or disable the JDayChooser.
672 *
673 * @param enabled
674 * The new enabled value
675 */
676 public void setEnabled(boolean enabled) {
677 super.setEnabled(enabled);
678
679 for (short i = 0; i < days.length; i++) {
680 if (days[i] != null) {
681 days[i].setEnabled(enabled);
682 }
683 }
684
685 for (short i = 0; i < weeks.length; i++) {
686 if (weeks[i] != null) {
687 weeks[i].setEnabled(enabled);
688 }
689 }
690 }
691
692 /**
693 * In some Countries it is often usefull to know in which week of the year a
694 * date is.
695 *
696 * @return boolean true, if the weeks of the year is shown
697 */
698 public boolean isWeekOfYearVisible() {
699 return weekOfYearVisible;
700 }
701
702 /**
703 * In some Countries it is often usefull to know in which week of the year a
704 * date is.
705 *
706 * @param weekOfYearVisible
707 * true, if the weeks of the year shall be shown
708 */
709 public void setWeekOfYearVisible(boolean weekOfYearVisible) {
710 if (weekOfYearVisible == this.weekOfYearVisible) {
711 return;
712 } else if (weekOfYearVisible) {
713 add(weekPanel, BorderLayout.WEST);
714 } else {
715 remove(weekPanel);
716 }
717
718 this.weekOfYearVisible = weekOfYearVisible;
719 validate();
720 dayPanel.validate();
721 }
722
723 /**
724 * Returns the day panel.
725 *
726 * @return the day panel
727 */
728 public JPanel getDayPanel() {
729 return dayPanel;
730 }
731
732 /**
733 * Returns the color of the decoration (day names and weeks).
734 *
735 * @return the color of the decoration (day names and weeks).
736 */
737 public Color getDecorationBackgroundColor() {
738 return decorationBackgroundColor;
739 }
740
741 /**
742 * Sets the background of days and weeks of year buttons.
743 *
744 * @param decorationBackgroundColor
745 * The background to set
746 */
747 public void setDecorationBackgroundColor(Color decorationBackgroundColor) {
748 this.decorationBackgroundColor = decorationBackgroundColor;
749
750 if (days != null) {
751 for (int i = 0; i < 7; i++) {
752 days[i].setBackground(decorationBackgroundColor);
753 }
754 }
755
756 if (weeks != null) {
757 for (int i = 0; i < 7; i++) {
758 weeks[i].setBackground(decorationBackgroundColor);
759 }
760 }
761 }
762
763 /**
764 * Returns the Sunday foreground.
765 *
766 * @return Color the Sunday foreground.
767 */
768 public Color getSundayForeground() {
769 return sundayForeground;
770 }
771
772 /**
773 * Returns the weekday foreground.
774 *
775 * @return Color the weekday foreground.
776 */
777 public Color getWeekdayForeground() {
778 return weekdayForeground;
779 }
780
781 /**
782 * Sets the Sunday foreground.
783 *
784 * @param sundayForeground
785 * The sundayForeground to set
786 */
787 public void setSundayForeground(Color sundayForeground) {
788 this.sundayForeground = sundayForeground;
789 drawDayNames();
790 drawDays();
791 }
792
793 /**
794 * Sets the weekday foreground.
795 *
796 * @param weekdayForeground
797 * The weekdayForeground to set
798 */
799 public void setWeekdayForeground(Color weekdayForeground) {
800 this.weekdayForeground = weekdayForeground;
801 drawDayNames();
802 drawDays();
803 }
804
805 /**
806 * Requests that the selected day also have the focus.
807 */
808 public void setFocus() {
809 if (selectedDay != null) {
810 this.selectedDay.requestFocus();
811 }
812 }
813
814 /**
815 * The decoration background is the background color of the day titles and
816 * the weeks of the year.
817 *
818 * @return Returns true, if the decoration background is painted.
819 */
820 public boolean isDecorationBackgroundVisible() {
821 return decorationBackgroundVisible;
822 }
823
824 /**
825 * The decoration background is the background color of the day titles and
826 * the weeks of the year.
827 *
828 * @param decorationBackgroundVisible
829 * true, if the decoration background shall be painted.
830 */
831 public void setDecorationBackgroundVisible(
832 boolean decorationBackgroundVisible) {
833 this.decorationBackgroundVisible = decorationBackgroundVisible;
834 initDecorations();
835 }
836
837 /**
838 * The decoration border is the button border of the day titles and the
839 * weeks of the year.
840 *
841 * @return Returns true, if the decoration border is painted.
842 */
843 public boolean isDecorationBordersVisible() {
844 return decorationBordersVisible;
845 }
846
847 public boolean isDayBordersVisible() {
848 return dayBordersVisible;
849 }
850
851 /**
852 * The decoration border is the button border of the day titles and the
853 * weeks of the year.
854 *
855 * @param decorationBordersVisible
856 * true, if the decoration border shall be painted.
857 */
858 public void setDecorationBordersVisible(boolean decorationBordersVisible) {
859 this.decorationBordersVisible = decorationBordersVisible;
860 initDecorations();
861 }
862
863 public void setDayBordersVisible(boolean dayBordersVisible) {
864 this.dayBordersVisible = dayBordersVisible;
865 if (initialized) {
866 for (int x = 7; x < 49; x++) {
867 if ("Windows".equals(UIManager.getLookAndFeel().getID())) {
868 days[x].setContentAreaFilled(dayBordersVisible);
869 } else {
870 days[x].setContentAreaFilled(true);
871 }
872 days[x].setBorderPainted(dayBordersVisible);
873 }
874 }
875 }
876
877 /**
878 * Updates the UI and sets the day button preferences.
879 */
880 public void updateUI() {
881 super.updateUI();
882 setFont(Font.decode("Dialog Plain 11"));
883
884 if (weekPanel != null) {
885 weekPanel.updateUI();
886 }
887 if (initialized) {
888 if ("Windows".equals(UIManager.getLookAndFeel().getID())) {
889 setDayBordersVisible(false);
890 setDecorationBackgroundVisible(true);
891 setDecorationBordersVisible(false);
892 } else {
893 setDayBordersVisible(true);
894 setDecorationBackgroundVisible(decorationBackgroundVisible);
895 setDecorationBordersVisible(decorationBordersVisible);
896 }
897 }
898 }
899
900 /**
901 * Sets a valid date range for selectable dates. If max is before min, the
902 * default range with no limitation is set.
903 *
904 * @param min
905 * the minimum selectable date or null (then the minimum date is
906 * set to 01\01\0001)
907 * @param max
908 * the maximum selectable date or null (then the maximum date is
909 * set to 01\01\9999)
910 */
911 public void setSelectableDateRange(Date min, Date max) {
912 if (min == null) {
913 minSelectableDate = defaultMinSelectableDate;
914 } else {
915 minSelectableDate = min;
916 }
917 if (max == null) {
918 maxSelectableDate = defaultMaxSelectableDate;
919 } else {
920 maxSelectableDate = max;
921 }
922 if (maxSelectableDate.before(minSelectableDate)) {
923 minSelectableDate = defaultMinSelectableDate;
924 maxSelectableDate = defaultMaxSelectableDate;
925 }
926 drawDays();
927 }
928
929 /**
930 * Sets the maximum selectable date. If null, the date 01\01\9999 will be
931 * set instead.
932 *
933 * @param max
934 * the maximum selectable date
935 *
936 * @return the maximum selectable date
937 */
938 public Date setMaxSelectableDate(Date max) {
939 if (max == null) {
940 maxSelectableDate = defaultMaxSelectableDate;
941 } else {
942 maxSelectableDate = max;
943 }
944 drawDays();
945 return maxSelectableDate;
946 }
947
948 /**
949 * Sets the minimum selectable date. If null, the date 01\01\0001 will be
950 * set instead.
951 *
952 * @param min
953 * the minimum selectable date
954 *
955 * @return the minimum selectable date
956 */
957 public Date setMinSelectableDate(Date min) {
958 if (min == null) {
959 minSelectableDate = defaultMinSelectableDate;
960 } else {
961 minSelectableDate = min;
962 }
963 drawDays();
964 return minSelectableDate;
965 }
966
967 /**
968 * Gets the maximum selectable date.
969 *
970 * @return the maximum selectable date
971 */
972 public Date getMaxSelectableDate() {
973 return maxSelectableDate;
974 }
975
976 /**
977 * Gets the minimum selectable date.
978 *
979 * @return the minimum selectable date
980 */
981 public Date getMinSelectableDate() {
982 return minSelectableDate;
983 }
984
985 /**
986 * Gets the maximum number of characters of a day name or 0. If 0 is
987 * returned, dateFormatSymbols.getShortWeekdays() will be used.
988 *
989 * @return the maximum number of characters of a day name or 0.
990 */
991 public int getMaxDayCharacters() {
992 return maxDayCharacters;
993 }
994
995 /**
996 * Sets the maximum number of characters per day in the day bar. Valid
997 * values are 0-4. If set to 0, dateFormatSymbols.getShortWeekdays() will be
998 * used, otherwise theses strings will be reduced to the maximum number of
999 * characters.
1000 *
1001 * @param maxDayCharacters
1002 * the maximum number of characters of a day name.
1003 */
1004 public void setMaxDayCharacters(int maxDayCharacters) {
1005 if (maxDayCharacters == this.maxDayCharacters) {
1006 return;
1007 }
1008
1009 if (maxDayCharacters < 0 || maxDayCharacters > 4) {
1010 this.maxDayCharacters = 0;
1011 } else {
1012 this.maxDayCharacters = maxDayCharacters;
1013 }
1014 drawDayNames();
1015 drawDays();
1016 invalidate();
1017 }
1018
1019 /**
1020 * Creates a JFrame with a JDayChooser inside and can be used for testing.
1021 *
1022 * @param s
1023 * The command line arguments
1024 */
1025 public static void main(String[] s) {
1026 JFrame frame = new JFrame("JDayChooser");
1027 frame.getContentPane().add(new JDayChooser());
1028 frame.pack();
1029 frame.setVisible(true);
1030 }
1031
1032 class DecoratorButton extends JButton {
1033 private static final long serialVersionUID = -5306477668406547496L;
1034
1035 public DecoratorButton() {
1036 setBackground(decorationBackgroundColor);
1037 setContentAreaFilled(decorationBackgroundVisible);
1038 setBorderPainted(decorationBordersVisible);
1039 }
1040
1041 public void addMouseListener(MouseListener l) {
1042 }
1043
1044 public boolean isFocusable() {
1045 return false;
1046 }
1047
1048 public void paint(Graphics g) {
1049 if ("Windows".equals(UIManager.getLookAndFeel().getID())) {
1050 // this is a hack to get the background painted
1051 // when using Windows Look & Feel
1052 if (decorationBackgroundVisible) {
1053 g.setColor(decorationBackgroundColor);
1054 } else {
1055 g.setColor(days[7].getBackground());
1056 }
1057 g.fillRect(0, 0, getWidth(), getHeight());
1058 if (isBorderPainted()) {
1059 setContentAreaFilled(true);
1060 } else {
1061 setContentAreaFilled(false);
1062 }
1063 }
1064 super.paint(g);
1065 }
1066 };
1067 }