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 044package org.jfree.ui; 045 046import java.awt.BorderLayout; 047import java.awt.Color; 048import java.awt.Font; 049import java.awt.GridLayout; 050import java.awt.Insets; 051import java.awt.event.ActionEvent; 052import java.awt.event.ActionListener; 053import java.util.Calendar; 054import java.util.Date; 055import java.util.Enumeration; 056import java.util.Vector; 057import javax.swing.BorderFactory; 058import javax.swing.JButton; 059import javax.swing.JComboBox; 060import javax.swing.JLabel; 061import javax.swing.JPanel; 062import javax.swing.SwingConstants; 063 064import 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 */ 073public 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}