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.5 2005/11/03 09:27:28 mungady 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 058 import javax.swing.BorderFactory; 059 import javax.swing.JButton; 060 import javax.swing.JComboBox; 061 import javax.swing.JLabel; 062 import javax.swing.JPanel; 063 import javax.swing.SwingConstants; 064 065 import org.jfree.date.SerialDate; 066 067 /** 068 * A panel that allows the user to select a date. 069 * <P> 070 * This class is incomplete and untested. You should not use it yet... 071 * 072 * @author David Gilbert 073 */ 074 public class SerialDateChooserPanel extends JPanel implements ActionListener { 075 076 /** The default background color for the selected date. */ 077 public static final Color DEFAULT_DATE_BUTTON_COLOR = Color.red; 078 079 /** The default background color for the current month. */ 080 public static final Color DEFAULT_MONTH_BUTTON_COLOR = Color.lightGray; 081 082 /** The date selected in the panel. */ 083 private SerialDate date; 084 085 /** The color for the selected date. */ 086 private Color dateButtonColor; 087 088 /** The color for dates in the current month. */ 089 private Color monthButtonColor; 090 091 /** The color for dates that are visible, but not in the current month. */ 092 private Color chosenOtherButtonColor = Color.darkGray; 093 094 /** The first day-of-the-week. */ 095 private int firstDayOfWeek = Calendar.SUNDAY; 096 097 /** The range used for selecting years. */ 098 private int yearSelectionRange = 20; 099 100 /** The font used to display the date. */ 101 private Font dateFont = new Font("SansSerif", Font.PLAIN, 10); 102 103 /** A combo for selecting the month. */ 104 private JComboBox monthSelector = null; 105 106 /** A combo for selecting the year. */ 107 private JComboBox yearSelector = null; 108 109 /** A button for selecting today's date. */ 110 private JButton todayButton = null; 111 112 /** An array of buttons used to display the days-of-the-month. */ 113 private JButton[] buttons = null; 114 115 /** A flag that indicates whether or not we are currently refreshing the buttons. */ 116 private boolean refreshing = false; 117 118 /** 119 * Constructs a new date chooser panel, using today's date as the initial selection. 120 */ 121 public SerialDateChooserPanel() { 122 123 this(SerialDate.createInstance(new Date()), false, 124 DEFAULT_DATE_BUTTON_COLOR, 125 DEFAULT_MONTH_BUTTON_COLOR); 126 127 } 128 129 /** 130 * Constructs a new date chooser panel. 131 * 132 * @param date the date. 133 * @param controlPanel a flag that indicates whether or not the 'today' button should 134 * appear on the panel. 135 */ 136 public SerialDateChooserPanel(final SerialDate date, final boolean controlPanel) { 137 138 this(date, controlPanel, 139 DEFAULT_DATE_BUTTON_COLOR, 140 DEFAULT_MONTH_BUTTON_COLOR); 141 142 } 143 144 /** 145 * Constructs a new date chooser panel. 146 * 147 * @param date the date. 148 * @param controlPanel the control panel. 149 * @param dateButtonColor the date button color. 150 * @param monthButtonColor the month button color. 151 */ 152 public SerialDateChooserPanel(final SerialDate date, final boolean controlPanel, 153 final Color dateButtonColor, final Color monthButtonColor) { 154 155 super(new BorderLayout()); 156 157 this.date = date; 158 this.dateButtonColor = dateButtonColor; 159 this.monthButtonColor = monthButtonColor; 160 161 add(constructSelectionPanel(), BorderLayout.NORTH); 162 add(getCalendarPanel(), BorderLayout.CENTER); 163 if (controlPanel) { 164 add(constructControlPanel(), BorderLayout.SOUTH); 165 } 166 167 } 168 169 /** 170 * Sets the date chosen in the panel. 171 * 172 * @param date the new date. 173 */ 174 public void setDate(final SerialDate date) { 175 176 this.date = date; 177 this.monthSelector.setSelectedIndex(date.getMonth() - 1); 178 refreshYearSelector(); 179 refreshButtons(); 180 181 } 182 183 /** 184 * Returns the date selected in the panel. 185 * 186 * @return the selected date. 187 */ 188 public SerialDate getDate() { 189 return this.date; 190 } 191 192 /** 193 * Handles action-events from the date panel. 194 * 195 * @param e information about the event that occurred. 196 */ 197 public void actionPerformed(final ActionEvent e) { 198 199 if (e.getActionCommand().equals("monthSelectionChanged")) { 200 final JComboBox c = (JComboBox) e.getSource(); 201 this.date = SerialDate.createInstance( 202 this.date.getDayOfMonth(), c.getSelectedIndex() + 1, this.date.getYYYY() 203 ); 204 refreshButtons(); 205 } 206 else if (e.getActionCommand().equals("yearSelectionChanged")) { 207 if (!this.refreshing) { 208 final JComboBox c = (JComboBox) e.getSource(); 209 final Integer y = (Integer) c.getSelectedItem(); 210 this.date = SerialDate.createInstance( 211 this.date.getDayOfMonth(), this.date.getMonth(), y.intValue() 212 ); 213 refreshYearSelector(); 214 refreshButtons(); 215 } 216 } 217 else if (e.getActionCommand().equals("todayButtonClicked")) { 218 setDate(SerialDate.createInstance(new Date())); 219 } 220 else if (e.getActionCommand().equals("dateButtonClicked")) { 221 final JButton b = (JButton) e.getSource(); 222 final int i = Integer.parseInt(b.getName()); 223 final SerialDate first = getFirstVisibleDate(); 224 final SerialDate selected = SerialDate.addDays(i, first); 225 setDate(selected); 226 } 227 228 } 229 230 /** 231 * Returns a panel of buttons, each button representing a day in the month. This is a 232 * sub-component of the DatePanel. 233 * 234 * @return the panel. 235 */ 236 private JPanel getCalendarPanel() { 237 238 final JPanel panel = new JPanel(new GridLayout(7, 7)); 239 panel.add(new JLabel("Sun", SwingConstants.CENTER)); 240 panel.add(new JLabel("Mon", SwingConstants.CENTER)); 241 panel.add(new JLabel("Tue", SwingConstants.CENTER)); 242 panel.add(new JLabel("Wed", SwingConstants.CENTER)); 243 panel.add(new JLabel("Thu", SwingConstants.CENTER)); 244 panel.add(new JLabel("Fri", SwingConstants.CENTER)); 245 panel.add(new JLabel("Sat", SwingConstants.CENTER)); 246 247 this.buttons = new JButton[42]; 248 for (int i = 0; i < 42; i++) { 249 final JButton button = new JButton(""); 250 button.setMargin(new Insets(1, 1, 1, 1)); 251 button.setName(Integer.toString(i)); 252 button.setFont(this.dateFont); 253 button.setFocusPainted(false); 254 button.setActionCommand("dateButtonClicked"); 255 button.addActionListener(this); 256 this.buttons[i] = button; 257 panel.add(button); 258 } 259 return panel; 260 261 } 262 263 /** 264 * Returns the button color according to the specified date. 265 * 266 * @param targetDate the target date. 267 * 268 * @return the button color. 269 */ 270 protected Color getButtonColor(final SerialDate targetDate) { 271 272 if (this.date.equals(this.date)) { 273 return this.dateButtonColor; 274 } 275 else if (targetDate.getMonth() == this.date.getMonth()) { 276 return this.monthButtonColor; 277 } 278 else { 279 return this.chosenOtherButtonColor; 280 } 281 282 } 283 284 /** 285 * Returns the first date that is visible in the grid. This should always be in the month 286 * preceding the month of the selected date. 287 * 288 * @return the first visible date. 289 */ 290 protected SerialDate getFirstVisibleDate() { 291 292 SerialDate result = SerialDate.createInstance(1, this.date.getMonth(), this.date.getYYYY()); 293 result = SerialDate.addDays(-1, result); 294 while (result.getDayOfWeek() != getFirstDayOfWeek()) { 295 result = SerialDate.addDays(-1, result); 296 } 297 return result; 298 299 } 300 301 /** 302 * Returns the first day of the week (controls the labels in the date panel). 303 * 304 * @return the first day of the week. 305 */ 306 private int getFirstDayOfWeek() { 307 return this.firstDayOfWeek; 308 } 309 310 /** 311 * Update the button labels and colors to reflect date selection. 312 */ 313 protected void refreshButtons() { 314 315 SerialDate current = getFirstVisibleDate(); 316 for (int i = 0; i < 42; i++) { 317 final JButton button = this.buttons[i]; 318 button.setText(String.valueOf(current.getDayOfWeek())); 319 button.setBackground(getButtonColor(current)); 320 current = SerialDate.addDays(1, current); 321 } 322 323 } 324 325 /** 326 * Changes the contents of the year selection JComboBox to reflect the chosen date and the year 327 * range. 328 */ 329 private void refreshYearSelector() { 330 if (!this.refreshing) { 331 this.refreshing = true; 332 this.yearSelector.removeAllItems(); 333 final Vector v = getYears(this.date.getYYYY()); 334 for (Enumeration e = v.elements(); e.hasMoreElements();) { 335 this.yearSelector.addItem(e.nextElement()); 336 } 337 this.yearSelector.setSelectedItem(new Integer(this.date.getYYYY())); 338 this.refreshing = false; 339 } 340 } 341 342 /** 343 * Returns a vector of years preceding and following the specified year. The number of years 344 * preceding and following is determined by the yearSelectionRange attribute. 345 * 346 * @param chosenYear the current year. 347 * 348 * @return a vector of years. 349 */ 350 private Vector getYears(final int chosenYear) { 351 final Vector v = new Vector(); 352 for (int i = chosenYear - this.yearSelectionRange; 353 i <= chosenYear + this.yearSelectionRange; i++) { 354 v.addElement(new Integer(i)); 355 } 356 return v; 357 } 358 359 /** 360 * Constructs a panel containing two JComboBoxes (for the month and year) and a button 361 * (to reset the date to TODAY). 362 * 363 * @return the panel. 364 */ 365 private JPanel constructSelectionPanel() { 366 final JPanel p = new JPanel(); 367 this.monthSelector = new JComboBox(SerialDate.getMonths()); 368 this.monthSelector.addActionListener(this); 369 this.monthSelector.setActionCommand("monthSelectionChanged"); 370 p.add(this.monthSelector); 371 372 this.yearSelector = new JComboBox(getYears(0)); 373 this.yearSelector.addActionListener(this); 374 this.yearSelector.setActionCommand("yearSelectionChanged"); 375 p.add(this.yearSelector); 376 377 return p; 378 } 379 380 /** 381 * Returns a panel that appears at the bottom of the calendar panel - contains a button for 382 * selecting today's date. 383 * 384 * @return the panel. 385 */ 386 private JPanel constructControlPanel() { 387 388 final JPanel p = new JPanel(); 389 p.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5)); 390 this.todayButton = new JButton("Today"); 391 this.todayButton.addActionListener(this); 392 this.todayButton.setActionCommand("todayButtonClicked"); 393 p.add(this.todayButton); 394 return p; 395 396 } 397 398 }