001 /* ========================================================================
002 * JCommon : a free general purpose class library for the Java(tm) platform
003 * ========================================================================
004 *
005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006 *
007 * Project Info: http://www.jfree.org/jcommon/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022 * USA.
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * ---------------------------
028 * SerialDateChooserPanel.java
029 * ---------------------------
030 * (C) Copyright 2001-2005, by Object Refinery Limited.
031 *
032 * Original Author: David Gilbert (for Object Refinery Limited);
033 * Contributor(s): -;
034 *
035 * $Id: SerialDateChooserPanel.java,v 1.7 2007/11/02 17:50:36 taqua Exp $
036 *
037 * Changes
038 * -------
039 * 08-Dec-2001 : Version 1 (DG);
040 * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
041 *
042 */
043
044 package org.jfree.ui;
045
046 import java.awt.BorderLayout;
047 import java.awt.Color;
048 import java.awt.Font;
049 import java.awt.GridLayout;
050 import java.awt.Insets;
051 import java.awt.event.ActionEvent;
052 import java.awt.event.ActionListener;
053 import java.util.Calendar;
054 import java.util.Date;
055 import java.util.Enumeration;
056 import java.util.Vector;
057 import javax.swing.BorderFactory;
058 import javax.swing.JButton;
059 import javax.swing.JComboBox;
060 import javax.swing.JLabel;
061 import javax.swing.JPanel;
062 import javax.swing.SwingConstants;
063
064 import org.jfree.date.SerialDate;
065
066 /**
067 * A panel that allows the user to select a date.
068 * <P>
069 * This class is incomplete and untested. You should not use it yet...
070 *
071 * @author David Gilbert
072 */
073 public class SerialDateChooserPanel extends JPanel implements ActionListener {
074
075 /** The default background color for the selected date. */
076 public static final Color DEFAULT_DATE_BUTTON_COLOR = Color.red;
077
078 /** The default background color for the current month. */
079 public static final Color DEFAULT_MONTH_BUTTON_COLOR = Color.lightGray;
080
081 /** The date selected in the panel. */
082 private SerialDate date;
083
084 /** The color for the selected date. */
085 private Color dateButtonColor;
086
087 /** The color for dates in the current month. */
088 private Color monthButtonColor;
089
090 /** The color for dates that are visible, but not in the current month. */
091 private Color chosenOtherButtonColor = Color.darkGray;
092
093 /** The first day-of-the-week. */
094 private int firstDayOfWeek = Calendar.SUNDAY;
095
096 /** The range used for selecting years. */
097 private int yearSelectionRange = 20;
098
099 /** The font used to display the date. */
100 private Font dateFont = new Font("SansSerif", Font.PLAIN, 10);
101
102 /** A combo for selecting the month. */
103 private JComboBox monthSelector = null;
104
105 /** A combo for selecting the year. */
106 private JComboBox yearSelector = null;
107
108 /** A button for selecting today's date. */
109 private JButton todayButton = null;
110
111 /** An array of buttons used to display the days-of-the-month. */
112 private JButton[] buttons = null;
113
114 /** A flag that indicates whether or not we are currently refreshing the buttons. */
115 private boolean refreshing = false;
116
117 /**
118 * Constructs a new date chooser panel, using today's date as the initial selection.
119 */
120 public SerialDateChooserPanel() {
121
122 this(SerialDate.createInstance(new Date()), false,
123 DEFAULT_DATE_BUTTON_COLOR,
124 DEFAULT_MONTH_BUTTON_COLOR);
125
126 }
127
128 /**
129 * Constructs a new date chooser panel.
130 *
131 * @param date the date.
132 * @param controlPanel a flag that indicates whether or not the 'today' button should
133 * appear on the panel.
134 */
135 public SerialDateChooserPanel(final SerialDate date, final boolean controlPanel) {
136
137 this(date, controlPanel,
138 DEFAULT_DATE_BUTTON_COLOR,
139 DEFAULT_MONTH_BUTTON_COLOR);
140
141 }
142
143 /**
144 * Constructs a new date chooser panel.
145 *
146 * @param date the date.
147 * @param controlPanel the control panel.
148 * @param dateButtonColor the date button color.
149 * @param monthButtonColor the month button color.
150 */
151 public SerialDateChooserPanel(final SerialDate date, final boolean controlPanel,
152 final Color dateButtonColor, final Color monthButtonColor) {
153
154 super(new BorderLayout());
155
156 this.date = date;
157 this.dateButtonColor = dateButtonColor;
158 this.monthButtonColor = monthButtonColor;
159
160 add(constructSelectionPanel(), BorderLayout.NORTH);
161 add(getCalendarPanel(), BorderLayout.CENTER);
162 if (controlPanel) {
163 add(constructControlPanel(), BorderLayout.SOUTH);
164 }
165
166 }
167
168 /**
169 * Sets the date chosen in the panel.
170 *
171 * @param date the new date.
172 */
173 public void setDate(final SerialDate date) {
174
175 this.date = date;
176 this.monthSelector.setSelectedIndex(date.getMonth() - 1);
177 refreshYearSelector();
178 refreshButtons();
179
180 }
181
182 /**
183 * Returns the date selected in the panel.
184 *
185 * @return the selected date.
186 */
187 public SerialDate getDate() {
188 return this.date;
189 }
190
191 /**
192 * Handles action-events from the date panel.
193 *
194 * @param e information about the event that occurred.
195 */
196 public void actionPerformed(final ActionEvent e) {
197
198 if (e.getActionCommand().equals("monthSelectionChanged")) {
199 final JComboBox c = (JComboBox) e.getSource();
200 this.date = SerialDate.createInstance(
201 this.date.getDayOfMonth(), c.getSelectedIndex() + 1, this.date.getYYYY()
202 );
203 refreshButtons();
204 }
205 else if (e.getActionCommand().equals("yearSelectionChanged")) {
206 if (!this.refreshing) {
207 final JComboBox c = (JComboBox) e.getSource();
208 final Integer y = (Integer) c.getSelectedItem();
209 this.date = SerialDate.createInstance(
210 this.date.getDayOfMonth(), this.date.getMonth(), y.intValue()
211 );
212 refreshYearSelector();
213 refreshButtons();
214 }
215 }
216 else if (e.getActionCommand().equals("todayButtonClicked")) {
217 setDate(SerialDate.createInstance(new Date()));
218 }
219 else if (e.getActionCommand().equals("dateButtonClicked")) {
220 final JButton b = (JButton) e.getSource();
221 final int i = Integer.parseInt(b.getName());
222 final SerialDate first = getFirstVisibleDate();
223 final SerialDate selected = SerialDate.addDays(i, first);
224 setDate(selected);
225 }
226
227 }
228
229 /**
230 * Returns a panel of buttons, each button representing a day in the month. This is a
231 * sub-component of the DatePanel.
232 *
233 * @return the panel.
234 */
235 private JPanel getCalendarPanel() {
236
237 final JPanel panel = new JPanel(new GridLayout(7, 7));
238 panel.add(new JLabel("Sun", SwingConstants.CENTER));
239 panel.add(new JLabel("Mon", SwingConstants.CENTER));
240 panel.add(new JLabel("Tue", SwingConstants.CENTER));
241 panel.add(new JLabel("Wed", SwingConstants.CENTER));
242 panel.add(new JLabel("Thu", SwingConstants.CENTER));
243 panel.add(new JLabel("Fri", SwingConstants.CENTER));
244 panel.add(new JLabel("Sat", SwingConstants.CENTER));
245
246 this.buttons = new JButton[42];
247 for (int i = 0; i < 42; i++) {
248 final JButton button = new JButton("");
249 button.setMargin(new Insets(1, 1, 1, 1));
250 button.setName(Integer.toString(i));
251 button.setFont(this.dateFont);
252 button.setFocusPainted(false);
253 button.setActionCommand("dateButtonClicked");
254 button.addActionListener(this);
255 this.buttons[i] = button;
256 panel.add(button);
257 }
258 return panel;
259
260 }
261
262 /**
263 * Returns the button color according to the specified date.
264 *
265 * @param targetDate the target date.
266 *
267 * @return the button color.
268 */
269 protected Color getButtonColor(final SerialDate targetDate) {
270
271 if (this.date.equals(this.date)) {
272 return this.dateButtonColor;
273 }
274 else if (targetDate.getMonth() == this.date.getMonth()) {
275 return this.monthButtonColor;
276 }
277 else {
278 return this.chosenOtherButtonColor;
279 }
280
281 }
282
283 /**
284 * Returns the first date that is visible in the grid. This should always be in the month
285 * preceding the month of the selected date.
286 *
287 * @return the first visible date.
288 */
289 protected SerialDate getFirstVisibleDate() {
290
291 SerialDate result = SerialDate.createInstance(1, this.date.getMonth(), this.date.getYYYY());
292 result = SerialDate.addDays(-1, result);
293 while (result.getDayOfWeek() != getFirstDayOfWeek()) {
294 result = SerialDate.addDays(-1, result);
295 }
296 return result;
297
298 }
299
300 /**
301 * Returns the first day of the week (controls the labels in the date panel).
302 *
303 * @return the first day of the week.
304 */
305 private int getFirstDayOfWeek() {
306 return this.firstDayOfWeek;
307 }
308
309 /**
310 * Update the button labels and colors to reflect date selection.
311 */
312 protected void refreshButtons() {
313
314 SerialDate current = getFirstVisibleDate();
315 for (int i = 0; i < 42; i++) {
316 final JButton button = this.buttons[i];
317 button.setText(String.valueOf(current.getDayOfWeek()));
318 button.setBackground(getButtonColor(current));
319 current = SerialDate.addDays(1, current);
320 }
321
322 }
323
324 /**
325 * Changes the contents of the year selection JComboBox to reflect the chosen date and the year
326 * range.
327 */
328 private void refreshYearSelector() {
329 if (!this.refreshing) {
330 this.refreshing = true;
331 this.yearSelector.removeAllItems();
332 final Vector v = getYears(this.date.getYYYY());
333 for (Enumeration e = v.elements(); e.hasMoreElements();) {
334 this.yearSelector.addItem(e.nextElement());
335 }
336 this.yearSelector.setSelectedItem(new Integer(this.date.getYYYY()));
337 this.refreshing = false;
338 }
339 }
340
341 /**
342 * Returns a vector of years preceding and following the specified year. The number of years
343 * preceding and following is determined by the yearSelectionRange attribute.
344 *
345 * @param chosenYear the current year.
346 *
347 * @return a vector of years.
348 */
349 private Vector getYears(final int chosenYear) {
350 final Vector v = new Vector();
351 for (int i = chosenYear - this.yearSelectionRange;
352 i <= chosenYear + this.yearSelectionRange; i++) {
353 v.addElement(new Integer(i));
354 }
355 return v;
356 }
357
358 /**
359 * Constructs a panel containing two JComboBoxes (for the month and year) and a button
360 * (to reset the date to TODAY).
361 *
362 * @return the panel.
363 */
364 private JPanel constructSelectionPanel() {
365 final JPanel p = new JPanel();
366 this.monthSelector = new JComboBox(SerialDate.getMonths());
367 this.monthSelector.addActionListener(this);
368 this.monthSelector.setActionCommand("monthSelectionChanged");
369 p.add(this.monthSelector);
370
371 this.yearSelector = new JComboBox(getYears(0));
372 this.yearSelector.addActionListener(this);
373 this.yearSelector.setActionCommand("yearSelectionChanged");
374 p.add(this.yearSelector);
375
376 return p;
377 }
378
379 /**
380 * Returns a panel that appears at the bottom of the calendar panel - contains a button for
381 * selecting today's date.
382 *
383 * @return the panel.
384 */
385 private JPanel constructControlPanel() {
386
387 final JPanel p = new JPanel();
388 p.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
389 this.todayButton = new JButton("Today");
390 this.todayButton.addActionListener(this);
391 this.todayButton.setActionCommand("todayButtonClicked");
392 p.add(this.todayButton);
393 return p;
394
395 }
396
397 }