KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > ui > DateChooserPanel


1 /* ========================================================================
2  * JCommon : a free general purpose class library for the Java(tm) platform
3  * ========================================================================
4  *
5  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jcommon/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * ---------------------
28  * DateChooserPanel.java
29  * ---------------------
30  * (C) Copyright 2000-2004, by Object Refinery Limited.
31  *
32  * Original Author: David Gilbert (for Object Refinery Limited);
33  * Contributor(s): -;
34  *
35  * $Id: DateChooserPanel.java,v 1.10 2005/11/16 15:58:41 taqua Exp $
36  *
37  * Changes (from 26-Oct-2001)
38  * --------------------------
39  * 26-Oct-2001 : Changed package to com.jrefinery.ui.* (DG);
40  * 08-Dec-2001 : Dropped the getMonths() method (DG);
41  * 13-Oct-2002 : Fixed errors reported by Checkstyle (DG);
42  * 02-Nov-2005 : Fixed a bug where the current day-of-the-month is past
43  * the end of the newly selected month when the month or year
44  * combo boxes are changed - see bug id 1344319 (DG);
45  *
46  */

47
48 package org.jfree.ui;
49
50 import java.awt.BorderLayout JavaDoc;
51 import java.awt.Color JavaDoc;
52 import java.awt.Font JavaDoc;
53 import java.awt.GridLayout JavaDoc;
54 import java.awt.Insets JavaDoc;
55 import java.awt.event.ActionEvent JavaDoc;
56 import java.awt.event.ActionListener JavaDoc;
57 import java.text.DateFormatSymbols JavaDoc;
58 import java.util.Calendar JavaDoc;
59 import java.util.Date JavaDoc;
60
61 import javax.swing.BorderFactory JavaDoc;
62 import javax.swing.JButton JavaDoc;
63 import javax.swing.JComboBox JavaDoc;
64 import javax.swing.JLabel JavaDoc;
65 import javax.swing.JPanel JavaDoc;
66 import javax.swing.SwingConstants JavaDoc;
67 import javax.swing.UIManager JavaDoc;
68
69 import org.jfree.date.SerialDate;
70
71 /**
72  * A panel that allows the user to select a date.
73  *
74  * @author David Gilbert
75  */

76 public class DateChooserPanel extends JPanel JavaDoc implements ActionListener JavaDoc {
77
78     /**
79      * The date selected in the panel.
80      */

81     private Calendar JavaDoc chosenDate;
82
83     /**
84      * The color for the selected date.
85      */

86     private Color JavaDoc chosenDateButtonColor;
87
88     /**
89      * The color for dates in the current month.
90      */

91     private Color JavaDoc chosenMonthButtonColor;
92
93     /**
94      * The color for dates that are visible, but not in the current month.
95      */

96     private Color JavaDoc chosenOtherButtonColor;
97
98     /**
99      * The first day-of-the-week.
100      */

101     private int firstDayOfWeek;
102
103     /**
104      * The range used for selecting years.
105      */

106     private int yearSelectionRange = 20;
107
108     /**
109      * The font used to display the date.
110      */

111     private Font JavaDoc dateFont = new Font JavaDoc("SansSerif", Font.PLAIN, 10);
112
113     /**
114      * A combo for selecting the month.
115      */

116     private JComboBox JavaDoc monthSelector;
117
118     /**
119      * A combo for selecting the year.
120      */

121     private JComboBox JavaDoc yearSelector;
122
123     /**
124      * A button for selecting today's date.
125      */

126     private JButton JavaDoc todayButton;
127
128     /**
129      * An array of buttons used to display the days-of-the-month.
130      */

131     private JButton JavaDoc[] buttons;
132
133     /**
134      * A flag that indicates whether or not we are currently refreshing the
135      * buttons.
136      */

137     private boolean refreshing = false;
138
139     /**
140      * The ordered set of all seven days of a week,
141      * beginning with the 'firstDayOfWeek'.
142      */

143     private int[] WEEK_DAYS;
144
145     /**
146      * Constructs a new date chooser panel, using today's date as the initial
147      * selection.
148      */

149     public DateChooserPanel() {
150         this(Calendar.getInstance(), false);
151     }
152
153     /**
154      * Constructs a new date chooser panel.
155      *
156      * @param calendar the calendar controlling the date.
157      * @param controlPanel a flag that indicates whether or not the 'today'
158      * button should appear on the panel.
159      */

160     public DateChooserPanel(final Calendar JavaDoc calendar,
161                             final boolean controlPanel) {
162
163         super(new BorderLayout JavaDoc());
164
165         this.chosenDateButtonColor = UIManager.getColor("textHighlight");
166         this.chosenMonthButtonColor = UIManager.getColor("control");
167         this.chosenOtherButtonColor = UIManager.getColor("controlShadow");
168
169         // the default date is today...
170
this.chosenDate = calendar;
171         this.firstDayOfWeek = calendar.getFirstDayOfWeek();
172         this.WEEK_DAYS = new int[7];
173         for (int i = 0; i < 7; i++) {
174             this.WEEK_DAYS[i] = ((this.firstDayOfWeek + i - 1) % 7) + 1;
175         }
176
177         add(constructSelectionPanel(), BorderLayout.NORTH);
178         add(getCalendarPanel(), BorderLayout.CENTER);
179         if (controlPanel) {
180             add(constructControlPanel(), BorderLayout.SOUTH);
181         }
182         setDate(calendar.getTime());
183     }
184
185     /**
186      * Sets the date chosen in the panel.
187      *
188      * @param theDate the new date.
189      */

190     public void setDate(final Date JavaDoc theDate) {
191
192         this.chosenDate.setTime(theDate);
193         this.monthSelector.setSelectedIndex(this.chosenDate.get(
194                 Calendar.MONTH));
195         refreshYearSelector();
196         refreshButtons();
197
198     }
199
200     /**
201      * Returns the date selected in the panel.
202      *
203      * @return the selected date.
204      */

205     public Date JavaDoc getDate() {
206         return this.chosenDate.getTime();
207     }
208
209     /**
210      * Handles action-events from the date panel.
211      *
212      * @param e information about the event that occurred.
213      */

214     public void actionPerformed(final ActionEvent JavaDoc e) {
215
216         if (e.getActionCommand().equals("monthSelectionChanged")) {
217             final JComboBox JavaDoc c = (JComboBox JavaDoc) e.getSource();
218             
219             // In most cases, changing the month will not change the selected
220
// day. But if the selected day is 29, 30 or 31 and the newly
221
// selected month doesn't have that many days, we revert to the
222
// last day of the newly selected month...
223
int dayOfMonth = this.chosenDate.get(Calendar.DAY_OF_MONTH);
224             this.chosenDate.set(Calendar.DAY_OF_MONTH, 1);
225             this.chosenDate.set(Calendar.MONTH, c.getSelectedIndex());
226             int maxDayOfMonth = this.chosenDate.getActualMaximum(
227                     Calendar.DAY_OF_MONTH);
228             this.chosenDate.set(Calendar.DAY_OF_MONTH, Math.min(dayOfMonth,
229                     maxDayOfMonth));
230             refreshButtons();
231         }
232         else if (e.getActionCommand().equals("yearSelectionChanged")) {
233             if (!this.refreshing) {
234                 final JComboBox JavaDoc c = (JComboBox JavaDoc) e.getSource();
235                 final Integer JavaDoc y = (Integer JavaDoc) c.getSelectedItem();
236                 
237                 // in most cases, changing the year will not change the
238
// selected day. But if the selected day is Feb 29, and the
239
// newly selected year is not a leap year, we revert to
240
// Feb 28...
241
int dayOfMonth = this.chosenDate.get(Calendar.DAY_OF_MONTH);
242                 this.chosenDate.set(Calendar.DAY_OF_MONTH, 1);
243                 this.chosenDate.set(Calendar.YEAR, y.intValue());
244                 int maxDayOfMonth = this.chosenDate.getActualMaximum(
245                     Calendar.DAY_OF_MONTH);
246                 this.chosenDate.set(Calendar.DAY_OF_MONTH, Math.min(dayOfMonth,
247                     maxDayOfMonth));
248                 refreshYearSelector();
249                 refreshButtons();
250             }
251         }
252         else if (e.getActionCommand().equals("todayButtonClicked")) {
253             setDate(new Date JavaDoc());
254         }
255         else if (e.getActionCommand().equals("dateButtonClicked")) {
256             final JButton JavaDoc b = (JButton JavaDoc) e.getSource();
257             final int i = Integer.parseInt(b.getName());
258             final Calendar JavaDoc cal = getFirstVisibleDate();
259             cal.add(Calendar.DATE, i);
260             setDate(cal.getTime());
261         }
262     }
263
264     /**
265      * Returns a panel of buttons, each button representing a day in the month.
266      * This is a sub-component of the DatePanel.
267      *
268      * @return the panel.
269      */

270     private JPanel JavaDoc getCalendarPanel() {
271
272         final JPanel JavaDoc p = new JPanel JavaDoc(new GridLayout JavaDoc(7, 7));
273         final DateFormatSymbols JavaDoc dateFormatSymbols = new DateFormatSymbols JavaDoc();
274         final String JavaDoc[] weekDays = dateFormatSymbols.getShortWeekdays();
275
276         for (int i = 0; i < this.WEEK_DAYS.length; i++) {
277             p.add(new JLabel JavaDoc(weekDays[this.WEEK_DAYS[i]],
278                     SwingConstants.CENTER));
279         }
280
281         this.buttons = new JButton JavaDoc[42];
282         for (int i = 0; i < 42; i++) {
283             final JButton JavaDoc b = new JButton JavaDoc("");
284             b.setMargin(new Insets JavaDoc(1, 1, 1, 1));
285             b.setName(Integer.toString(i));
286             b.setFont(this.dateFont);
287             b.setFocusPainted(false);
288             b.setActionCommand("dateButtonClicked");
289             b.addActionListener(this);
290             this.buttons[i] = b;
291             p.add(b);
292         }
293         return p;
294
295     }
296
297     /**
298      * Returns the button color according to the specified date.
299      *
300      * @param theDate the date.
301      * @return the color.
302      */

303     private Color JavaDoc getButtonColor(final Calendar JavaDoc theDate) {
304         if (equalDates(theDate, this.chosenDate)) {
305             return this.chosenDateButtonColor;
306         }
307         else if (theDate.get(Calendar.MONTH) == this.chosenDate.get(
308                 Calendar.MONTH)) {
309             return this.chosenMonthButtonColor;
310         }
311         else {
312             return this.chosenOtherButtonColor;
313         }
314     }
315
316     /**
317      * Returns true if the two dates are equal (time of day is ignored).
318      *
319      * @param c1 the first date.
320      * @param c2 the second date.
321      * @return boolean.
322      */

323     private boolean equalDates(final Calendar JavaDoc c1, final Calendar JavaDoc c2) {
324         if ((c1.get(Calendar.DATE) == c2.get(Calendar.DATE))
325             && (c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH))
326             && (c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR))) {
327             return true;
328         }
329         else {
330             return false;
331         }
332     }
333
334     /**
335      * Returns the first date that is visible in the grid. This should always
336      * be in the month preceding the month of the selected date.
337      *
338      * @return the date.
339      */

340     private Calendar JavaDoc getFirstVisibleDate() {
341         final Calendar JavaDoc c = Calendar.getInstance();
342         c.set(this.chosenDate.get(Calendar.YEAR), this.chosenDate.get(
343                 Calendar.MONTH), 1);
344         c.add(Calendar.DATE, -1);
345         while (c.get(Calendar.DAY_OF_WEEK) != getFirstDayOfWeek()) {
346             c.add(Calendar.DATE, -1);
347         }
348         return c;
349     }
350
351     /**
352      * Returns the first day of the week (controls the labels in the date
353      * panel).
354      *
355      * @return the first day of the week.
356      */

357     private int getFirstDayOfWeek() {
358         return this.firstDayOfWeek;
359     }
360
361     /**
362      * Update the button labels and colors to reflect date selection.
363      */

364     private void refreshButtons() {
365         final Calendar JavaDoc c = getFirstVisibleDate();
366         for (int i = 0; i < 42; i++) {
367             final JButton JavaDoc b = this.buttons[i];
368             b.setText(Integer.toString(c.get(Calendar.DATE)));
369             b.setBackground(getButtonColor(c));
370             c.add(Calendar.DATE, 1);
371         }
372     }
373
374     /**
375      * Changes the contents of the year selection JComboBox to reflect the
376      * chosen date and the year range.
377      */

378     private void refreshYearSelector() {
379         if (!this.refreshing) {
380             this.refreshing = true;
381             this.yearSelector.removeAllItems();
382             final Integer JavaDoc[] years = getYears(this.chosenDate.get(
383                     Calendar.YEAR));
384             for (int i = 0; i < years.length; i++) {
385                 this.yearSelector.addItem(years[i]);
386             }
387             this.yearSelector.setSelectedItem(new Integer JavaDoc(this.chosenDate.get(
388                     Calendar.YEAR)));
389             this.refreshing = false;
390         }
391     }
392
393     /**
394      * Returns a vector of years preceding and following the specified year.
395      * The number of years preceding and following is determined by the
396      * yearSelectionRange attribute.
397      *
398      * @param chosenYear the selected year.
399      * @return a vector of years.
400      */

401     private Integer JavaDoc[] getYears(final int chosenYear) {
402         final int size = this.yearSelectionRange * 2 + 1;
403         final int start = chosenYear - this.yearSelectionRange;
404
405         final Integer JavaDoc[] years = new Integer JavaDoc[size];
406         for (int i = 0; i < size; i++) {
407             years[i] = new Integer JavaDoc(i + start);
408         }
409         return years;
410     }
411
412     /**
413      * Constructs a panel containing two JComboBoxes (for the month and year)
414      * and a button (to reset the date to TODAY).
415      *
416      * @return the panel.
417      */

418     private JPanel JavaDoc constructSelectionPanel() {
419         final JPanel JavaDoc p = new JPanel JavaDoc();
420
421         final int minMonth = this.chosenDate.getMinimum(Calendar.MONTH);
422         final int maxMonth = this.chosenDate.getMaximum(Calendar.MONTH);
423         final String JavaDoc[] months = new String JavaDoc[maxMonth - minMonth + 1];
424         System.arraycopy(SerialDate.getMonths(), minMonth, months, 0,
425                 months.length);
426
427         this.monthSelector = new JComboBox JavaDoc(months);
428         this.monthSelector.addActionListener(this);
429         this.monthSelector.setActionCommand("monthSelectionChanged");
430         p.add(this.monthSelector);
431
432         this.yearSelector = new JComboBox JavaDoc(getYears(0));
433         this.yearSelector.addActionListener(this);
434         this.yearSelector.setActionCommand("yearSelectionChanged");
435         p.add(this.yearSelector);
436
437         return p;
438     }
439
440     /**
441      * Returns a panel that appears at the bottom of the calendar panel -
442      * contains a button for selecting today's date.
443      *
444      * @return the panel.
445      */

446     private JPanel JavaDoc constructControlPanel() {
447
448         final JPanel JavaDoc p = new JPanel JavaDoc();
449         p.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
450         this.todayButton = new JButton JavaDoc("Today");
451         this.todayButton.addActionListener(this);
452         this.todayButton.setActionCommand("todayButtonClicked");
453         p.add(this.todayButton);
454         return p;
455
456     }
457
458     /**
459      * Returns the color for the currently selected date.
460      *
461      * @return a color.
462      */

463     public Color JavaDoc getChosenDateButtonColor() {
464         return this.chosenDateButtonColor;
465     }
466
467     /**
468      * Redefines the color for the currently selected date.
469      *
470      * @param chosenDateButtonColor the new color
471      */

472     public void setChosenDateButtonColor(final Color JavaDoc chosenDateButtonColor) {
473         if (chosenDateButtonColor == null) {
474             throw new NullPointerException JavaDoc("UIColor must not be null.");
475         }
476         final Color JavaDoc oldValue = this.chosenDateButtonColor;
477         this.chosenDateButtonColor = chosenDateButtonColor;
478         refreshButtons();
479         firePropertyChange("chosenDateButtonColor", oldValue,
480                 chosenDateButtonColor);
481     }
482
483     /**
484      * Returns the color for the buttons representing the current month.
485      *
486      * @return the color for the current month.
487      */

488     public Color JavaDoc getChosenMonthButtonColor() {
489         return this.chosenMonthButtonColor;
490     }
491
492     /**
493      * Defines the color for the buttons representing the current month.
494      *
495      * @param chosenMonthButtonColor the color for the current month.
496      */

497     public void setChosenMonthButtonColor(final Color JavaDoc chosenMonthButtonColor) {
498         if (chosenMonthButtonColor == null) {
499             throw new NullPointerException JavaDoc("UIColor must not be null.");
500         }
501         final Color JavaDoc oldValue = this.chosenMonthButtonColor;
502         this.chosenMonthButtonColor = chosenMonthButtonColor;
503         refreshButtons();
504         firePropertyChange("chosenMonthButtonColor", oldValue,
505                 chosenMonthButtonColor);
506     }
507
508     /**
509      * Returns the color for the buttons representing the other months.
510      *
511      * @return a color.
512      */

513     public Color JavaDoc getChosenOtherButtonColor() {
514         return this.chosenOtherButtonColor;
515     }
516
517     /**
518      * Redefines the color for the buttons representing the other months.
519      *
520      * @param chosenOtherButtonColor a color.
521      */

522     public void setChosenOtherButtonColor(final Color JavaDoc chosenOtherButtonColor) {
523         if (chosenOtherButtonColor == null) {
524             throw new NullPointerException JavaDoc("UIColor must not be null.");
525         }
526         final Color JavaDoc oldValue = this.chosenOtherButtonColor;
527         this.chosenOtherButtonColor = chosenOtherButtonColor;
528         refreshButtons();
529         firePropertyChange("chosenOtherButtonColor", oldValue,
530                 chosenOtherButtonColor);
531     }
532
533     /**
534      * Returns the range of years available for selection (defaults to 20).
535      *
536      * @return The range.
537      */

538     public int getYearSelectionRange() {
539         return this.yearSelectionRange;
540     }
541
542     /**
543      * Sets the range of years available for selection.
544      *
545      * @param yearSelectionRange the range.
546      */

547     public void setYearSelectionRange(final int yearSelectionRange) {
548         final int oldYearSelectionRange = this.yearSelectionRange;
549         this.yearSelectionRange = yearSelectionRange;
550         refreshYearSelector();
551         firePropertyChange("yearSelectionRange", oldYearSelectionRange,
552                 yearSelectionRange);
553     }
554 }
555
Popular Tags