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