JXMonthView.java
资源名称:swingx.zip [点击查看]
上传用户:zhengdagz
上传日期:2014-03-06
资源大小:1956k
文件大小:81k
源码类别:
xml/soap/webservice
开发平台:
Java
- /*
- * $Id: JXMonthView.java,v 1.12 2005/10/10 18:02:45 rbair Exp $
- *
- * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
- * Santa Clara, California 95054, U.S.A. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
- package org.jdesktop.swingx.calendar;
- import java.awt.*;
- import java.awt.event.*;
- import java.text.SimpleDateFormat;
- import java.text.DateFormatSymbols;
- import java.util.Calendar;
- import java.util.Date;
- import java.util.Hashtable;
- import java.util.TimeZone;
- import javax.swing.*;
- import javax.swing.border.Border;
- /**
- * Component that displays a month calendar which can be used to select a day
- * or range of days. By default the <code>JXMonthView</code> will display a
- * single calendar using the current month and year, using
- * <code>Calendar.SUNDAY</code> as the first day of the week.
- * <p>
- * The <code>JXMonthView</code> can be configured to display more than one
- * calendar at a time by calling
- * <code>setPreferredCalCols</code>/<code>setPreferredCalRows</code>. These
- * methods will set the preferred number of calendars to use in each
- * column/row. As these values change, the <code>Dimension</code> returned
- * from <code>getMinimumSize</code> and <code>getPreferredSize</code> will
- * be updated. The following example shows how to create a 2x2 view which is
- * contained within a <code>JFrame</code>:
- * <pre>
- * JXMonthView monthView = new JXMonthView();
- * monthView.setPreferredCols(2);
- * monthView.setPreferredRows(2);
- *
- * JFrame frame = new JFrame();
- * frame.getContentPane().add(monthView);
- * frame.pack();
- * frame.setVisible(true);
- * </pre>
- * <p>
- * <code>JXMonthView</code> can be further configured to allow any day of the
- * week to be considered the first day of the week. Character
- * representation of those days may also be set by providing an array of
- * strings.
- * <pre>
- * monthView.setFirstDayOfWeek(Calendar.MONDAY);
- * monthView.setDaysOfTheWeek(
- * new String[]{"S", "M", "T", "W", "Th", "F", "S"});
- * </pre>
- * <p>
- * This component supports flagging days. These flagged days, which must be
- * provided in sorted order, are displayed in a bold font. This can be used to
- * inform the user of such things as scheduled appointment.
- * <pre>
- * // Create some dates that we want to flag as being important.
- * Calendar cal1 = Calendar.getInstance();
- * cal1.set(2004, 1, 1);
- * Calendar cal2 = Calendar.getInstance();
- * cal2.set(2004, 1, 5);
- *
- * long[] flaggedDates = new long[] {
- * cal1.getTimeInMillis(),
- * cal2.getTimeInMillis(),
- * System.currentTimeMillis()
- * };
- *
- * // Sort them in ascending order.
- * java.util.Arrays.sort(flaggedDates);
- * monthView.setFlaggedDates(flaggedDates);
- * </pre>
- * Applications may have the need to allow users to select different ranges of
- * dates. There are four modes of selection that are supported, single,
- * multiple, week and no selection. Once a selection is made an action is
- * fired, with exception of the no selection mode, to inform listeners that
- * selection has changed.
- * <pre>
- * // Change the selection mode to select full weeks.
- * monthView.setSelectionMode(JXMonthView.WEEK_SELECTION);
- *
- * // Add an action listener that will be notified when the user
- * // changes selection via the mouse.
- * monthView.addActionListener(new ActionListener() {
- * public void actionPerformed(ActionEvent e) {
- * System.out.println(
- * ((JXMonthView)e.getSource()).getSelectedDateSpan());
- * }
- * });
- * </pre>
- *
- * @author Joshua Outwater
- * @version $Revision: 1.12 $
- */
- public class JXMonthView extends JComponent {
- /** Mode that disallows selection of days from the calendar. */
- public static final int NO_SELECTION = 0;
- /** Mode that allows for selection of a single day. */
- public static final int SINGLE_SELECTION = 1;
- /** Mode that allows for selecting of multiple consecutive days. */
- public static final int MULTIPLE_SELECTION = 2;
- /**
- * Mode where selections consisting of more than 7 days will
- * snap to a full week.
- */
- public static final int WEEK_SELECTION = 3;
- /** Return value used to identify when the month down button is pressed. */
- public static final int MONTH_DOWN = 1;
- /** Return value used to identify when the month up button is pressed. */
- public static final int MONTH_UP = 2;
- /**
- * Insets used in determining the rectangle for the month string
- * background.
- */
- protected Insets _monthStringInsets = new Insets(0,0,0,0);
- private static final int MONTH_DROP_SHADOW = 1;
- private static final int MONTH_LINE_DROP_SHADOW = 2;
- private static final int WEEK_DROP_SHADOW = 4;
- private int _boxPaddingX = 3;
- private int _boxPaddingY = 3;
- private int _arrowPaddingX = 3;
- private int _arrowPaddingY = 3;
- private static final int CALENDAR_SPACING = 10;
- private static final int DAYS_IN_WEEK = 7;
- private static final int MONTHS_IN_YEAR = 12;
- /**
- * Keeps track of the first date we are displaying. We use this as a
- * restore point for the calendar.
- */
- private long _firstDisplayedDate;
- private int _firstDisplayedMonth;
- private int _firstDisplayedYear;
- private long _lastDisplayedDate;
- private Font _derivedFont;
- /** Beginning date of selection. -1 if no date is selected. */
- private long _startSelectedDate = -1;
- /** End date of selection. -1 if no date is selected. */
- private long _endSelectedDate = -1;
- /** For multiple selection we need to record the date we pivot around. */
- private long _pivotDate = -1;
- /** The number of calendars able to be displayed horizontally. */
- private int _numCalCols = 1;
- /** The number of calendars able to be displayed vertically. */
- private int _numCalRows = 1;
- private int _minCalCols = 1;
- private int _minCalRows = 1;
- private long _today;
- private long[] _flaggedDates;
- private int _selectionMode = SINGLE_SELECTION;
- private int _boxHeight;
- private int _boxWidth;
- private int _monthBoxHeight;
- private int _calendarWidth;
- private int _calendarHeight;
- private int _firstDayOfWeek = Calendar.SUNDAY;
- private int _startX;
- private int _startY;
- private int _dropShadowMask = 0;
- private boolean _dirty = false;
- private boolean _antiAlias = false;
- private boolean _ltr;
- private boolean _traversable = false;
- private boolean _usingKeyboard = false;
- private boolean _asKirkWouldSay_FIRE = false;
- private Calendar _cal;
- private String[] _daysOfTheWeek;
- private static String[] _monthsOfTheYear;
- private Dimension _dim = new Dimension();
- private Rectangle _bounds = new Rectangle();
- private Rectangle _dirtyRect = new Rectangle();
- private Color _todayBackgroundColor;
- private Color _monthStringBackground;
- private Color _monthStringForeground;
- private Color _daysOfTheWeekForeground;
- private Color _selectedBackground;
- private SimpleDateFormat _dayOfMonthFormatter = new SimpleDateFormat("d");
- private String _actionCommand = "selectionChanged";
- private Timer _todayTimer = null;
- private ImageIcon _monthDownImage;
- private ImageIcon _monthUpImage;
- private Hashtable<Integer, Color> _dayToColorTable = new Hashtable<Integer, Color>();
- /**
- * Date span used by the keyboard actions to track the original selection.
- */
- private DateSpan _originalDateSpan = null;
- /**
- * Create a new instance of the <code>JXMonthView</code> class using the
- * month and year of the current day as the first date to display.
- */
- public JXMonthView() {
- this(new Date().getTime());
- }
- /**
- * Create a new instance of the <code>JXMonthView</code> class using the
- * month and year from <code>initialTime</code> as the first date to
- * display.
- *
- * @param initialTime The first month to display.
- */
- public JXMonthView(long initialTime) {
- super();
- _ltr = getComponentOrientation().isLeftToRight();
- // Set up calendar instance.
- _cal = Calendar.getInstance(getLocale());
- _cal.setFirstDayOfWeek(_firstDayOfWeek);
- _cal.setMinimalDaysInFirstWeek(1);
- // Keep track of today.
- _cal.set(Calendar.HOUR_OF_DAY, 0);
- _cal.set(Calendar.MINUTE, 0);
- _cal.set(Calendar.SECOND, 0);
- _cal.set(Calendar.MILLISECOND, 0);
- _today = _cal.getTimeInMillis();
- _cal.setTimeInMillis(initialTime);
- setFirstDisplayedDate(_cal.getTimeInMillis());
- // Get string representation of the months of the year.
- _monthsOfTheYear = new DateFormatSymbols().getMonths();
- setOpaque(true);
- setBackground(Color.WHITE);
- setFocusable(true);
- _todayBackgroundColor = getForeground();
- // Restore original time value.
- _cal.setTimeInMillis(_firstDisplayedDate);
- enableEvents(AWTEvent.MOUSE_EVENT_MASK);
- enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
- // Setup the keyboard handler.
- InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "acceptSelection");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), "cancelSelection");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "selectPreviousDay");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "selectNextDay");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "selectDayInPreviousWeek");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "selectDayInNextWeek");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.SHIFT_MASK, false), "addPreviousDay");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.SHIFT_MASK, false), "addNextDay");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.SHIFT_MASK, false), "addToPreviousWeek");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.SHIFT_MASK, false), "addToNextWeek");
- // Needed to allow for keyboard control in popups.
- inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "acceptSelection");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), "cancelSelection");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "selectPreviousDay");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "selectNextDay");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "selectDayInPreviousWeek");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "selectDayInNextWeek");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.SHIFT_MASK, false), "addPreviousDay");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.SHIFT_MASK, false), "addNextDay");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.SHIFT_MASK, false), "addToPreviousWeek");
- inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.SHIFT_MASK, false), "addToNextWeek");
- ActionMap actionMap = getActionMap();
- actionMap.put("acceptSelection", new KeyboardAction(KeyboardAction.ACCEPT_SELECTION));
- actionMap.put("cancelSelection", new KeyboardAction(KeyboardAction.CANCEL_SELECTION));
- actionMap.put("selectPreviousDay", new KeyboardAction(KeyboardAction.SELECT_PREVIOUS_DAY));
- actionMap.put("selectNextDay", new KeyboardAction(KeyboardAction.SELECT_NEXT_DAY));
- actionMap.put("selectDayInPreviousWeek", new KeyboardAction(KeyboardAction.SELECT_DAY_PREVIOUS_WEEK));
- actionMap.put("selectDayInNextWeek", new KeyboardAction(KeyboardAction.SELECT_DAY_NEXT_WEEK));
- actionMap.put("addPreviousDay", new KeyboardAction(KeyboardAction.ADD_PREVIOUS_DAY));
- actionMap.put("addNextDay", new KeyboardAction(KeyboardAction.ADD_NEXT_DAY));
- actionMap.put("addToPreviousWeek", new KeyboardAction(KeyboardAction.ADD_TO_PREVIOUS_WEEK));
- actionMap.put("addToNextWeek", new KeyboardAction(KeyboardAction.ADD_TO_NEXT_WEEK));
- updateUI();
- }
- /**
- * Resets the UI property to a value from the current look and feel.
- */
- public void updateUI() {
- super.updateUI();
- String[] daysOfTheWeek =
- (String[])UIManager.get("JXMonthView.daysOfTheWeek");
- if (daysOfTheWeek == null) {
- String[] dateFormatSymbols =
- new DateFormatSymbols().getShortWeekdays();
- daysOfTheWeek = new String[DAYS_IN_WEEK];
- for (int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
- daysOfTheWeek[i - 1] = dateFormatSymbols[i];
- }
- }
- setDaysOfTheWeek(daysOfTheWeek);
- Color color =
- UIManager.getColor("JXMonthView.monthStringBackground");
- if (color == null) {
- color = new Color(138, 173, 209);
- }
- setMonthStringBackground(color);
- color = UIManager.getColor("JXMonthView.monthStringForeground");
- if (color == null) {
- color = new Color(68, 68, 68);
- }
- setMonthStringForeground(color);
- color = UIManager.getColor("JXMonthView.daysOfTheWeekForeground");
- if (color == null) {
- color = new Color(68, 68, 68);
- }
- setDaysOfTheWeekForeground(color);
- color = UIManager.getColor("JXMonthView.selectedBackground");
- if (color == null) {
- color = new Color(197, 220, 240);
- }
- setSelectedBackground(color);
- Font font = UIManager.getFont("JXMonthView.font");
- if (font == null) {
- font = UIManager.getFont("Button.font");
- }
- setFont(font);
- String imageLocation =
- UIManager.getString("JXMonthView.monthDownFileName");
- if (imageLocation == null) {
- imageLocation = "resources/month-down.png";
- }
- _monthDownImage = new ImageIcon(
- JXMonthView.class.getResource(imageLocation));
- imageLocation = UIManager.getString("JXMonthView.monthUpFileName");
- if (imageLocation == null) {
- imageLocation = "resources/month-up.png";
- }
- _monthUpImage = new ImageIcon(
- JXMonthView.class.getResource(imageLocation));
- }
- /**
- * Returns the first displayed date.
- *
- * @return long The first displayed date.
- */
- public long getFirstDisplayedDate() {
- return _firstDisplayedDate;
- }
- /**
- * Set the first displayed date. We only use the month and year of
- * this date. The <code>Calendar.DAY_OF_MONTH</code> field is reset to
- * 1 and all other fields, with exception of the year and month ,
- * are reset to 0.
- *
- * @param date The first displayed date.
- */
- public void setFirstDisplayedDate(long date) {
- long old = _firstDisplayedDate;
- _cal.setTimeInMillis(date);
- _cal.set(Calendar.DAY_OF_MONTH, 1);
- _cal.set(Calendar.HOUR_OF_DAY, 0);
- _cal.set(Calendar.MINUTE, 0);
- _cal.set(Calendar.SECOND, 0);
- _cal.set(Calendar.MILLISECOND, 0);
- _firstDisplayedDate = _cal.getTimeInMillis();
- _firstDisplayedMonth = _cal.get(Calendar.MONTH);
- _firstDisplayedYear = _cal.get(Calendar.YEAR);
- calculateLastDisplayedDate();
- firePropertyChange("firstDisplayedDate", old, _firstDisplayedDate);
- repaint();
- }
- /**
- * Returns the last date able to be displayed. For example, if the last
- * visible month was April the time returned would be April 30, 23:59:59.
- *
- * @return long The last displayed date.
- */
- public long getLastDisplayedDate() {
- return _lastDisplayedDate;
- }
- private void calculateLastDisplayedDate() {
- long old = _lastDisplayedDate;
- _cal.setTimeInMillis(_firstDisplayedDate);
- // Figure out the last displayed date.
- _cal.add(Calendar.MONTH, ((_numCalCols * _numCalRows) - 1));
- _cal.set(Calendar.DAY_OF_MONTH,
- _cal.getActualMaximum(Calendar.DAY_OF_MONTH));
- _cal.set(Calendar.HOUR_OF_DAY, 23);
- _cal.set(Calendar.MINUTE, 59);
- _cal.set(Calendar.SECOND, 59);
- _lastDisplayedDate = _cal.getTimeInMillis();
- firePropertyChange("lastDisplayedDate", old, _lastDisplayedDate);
- }
- /**
- * Moves the <code>date</code> into the visible region of the calendar.
- * If the date is greater than the last visible date it will become the
- * last visible date. While if it is less than the first visible date
- * it will become the first visible date.
- *
- * @param date Date to make visible.
- */
- public void ensureDateVisible(long date) {
- if (date < _firstDisplayedDate) {
- setFirstDisplayedDate(date);
- } else if (date > _lastDisplayedDate) {
- _cal.setTimeInMillis(date);
- int month = _cal.get(Calendar.MONTH);
- int year = _cal.get(Calendar.YEAR);
- _cal.setTimeInMillis(_lastDisplayedDate);
- int lastMonth = _cal.get(Calendar.MONTH);
- int lastYear = _cal.get(Calendar.YEAR);
- int diffMonths = month - lastMonth +
- ((year - lastYear) * MONTHS_IN_YEAR);
- _cal.setTimeInMillis(_firstDisplayedDate);
- _cal.add(Calendar.MONTH, diffMonths);
- setFirstDisplayedDate(_cal.getTimeInMillis());
- }
- if (_startSelectedDate != -1 || _endSelectedDate != -1) {
- calculateDirtyRectForSelection();
- }
- }
- /**
- * Returns a date span of the selected dates. The result will be null if
- * no dates are selected.
- */
- public DateSpan getSelectedDateSpan() {
- DateSpan result = null;
- if (_startSelectedDate != -1) {
- result = new DateSpan(new Date(_startSelectedDate),
- new Date(_endSelectedDate));
- }
- return result;
- }
- /**
- * Selects the dates in the DateSpan. This method will not change the
- * initial date displayed so the caller must update this if necessary.
- * If we are in SINGLE_SELECTION mode only the start time from the DateSpan
- * will be used. If we are in WEEK_SELECTION mode the span will be
- * modified to be valid if necessary.
- *
- * @param dateSpan DateSpan defining the selected dates. Passing
- * <code>null</code> will clear the selection.
- */
- public void setSelectedDateSpan(DateSpan dateSpan) {
- DateSpan oldSpan = null;
- if (_startSelectedDate != -1 && _endSelectedDate != -1) {
- oldSpan = new DateSpan(_startSelectedDate, _endSelectedDate);
- }
- if (dateSpan == null) {
- _startSelectedDate = -1;
- _endSelectedDate = -1;
- } else {
- _cal.setTimeInMillis(dateSpan.getStart());
- _cal.set(Calendar.HOUR_OF_DAY, 0);
- _cal.set(Calendar.MINUTE, 0);
- _cal.set(Calendar.SECOND, 0);
- _cal.set(Calendar.MILLISECOND, 0);
- _startSelectedDate = _cal.getTimeInMillis();
- if (_selectionMode == SINGLE_SELECTION) {
- _endSelectedDate = _startSelectedDate;
- } else {
- _cal.setTimeInMillis(dateSpan.getEnd());
- _cal.set(Calendar.HOUR_OF_DAY, 0);
- _cal.set(Calendar.MINUTE, 0);
- _cal.set(Calendar.SECOND, 0);
- _cal.set(Calendar.MILLISECOND, 0);
- _endSelectedDate = _cal.getTimeInMillis();
- if (_selectionMode == WEEK_SELECTION) {
- // Make sure if we are over 7 days we span full weeks.
- _cal.setTimeInMillis(_startSelectedDate);
- int count = 1;
- while (_cal.getTimeInMillis() < _endSelectedDate) {
- _cal.add(Calendar.DAY_OF_MONTH, 1);
- count++;
- }
- if (count > DAYS_IN_WEEK) {
- // Make sure start date is on the beginning of the
- // week.
- _cal.setTimeInMillis(_startSelectedDate);
- int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK);
- if (dayOfWeek != _firstDayOfWeek) {
- // Move the start date back to the first day of the
- // week.
- int daysFromStart = dayOfWeek - _firstDayOfWeek;
- if (daysFromStart < 0) {
- daysFromStart += DAYS_IN_WEEK;
- }
- _cal.add(Calendar.DAY_OF_MONTH, -daysFromStart);
- count += daysFromStart;
- _startSelectedDate = _cal.getTimeInMillis();
- }
- // Make sure we have full weeks. Otherwise modify the
- // end date.
- int remainder = count % DAYS_IN_WEEK;
- if (remainder != 0) {
- _cal.setTimeInMillis(_endSelectedDate);
- _cal.add(Calendar.DAY_OF_MONTH, (DAYS_IN_WEEK - remainder));
- _endSelectedDate = _cal.getTimeInMillis();
- }
- }
- }
- }
- // Restore original time value.
- _cal.setTimeInMillis(_firstDisplayedDate);
- }
- repaint(_dirtyRect);
- calculateDirtyRectForSelection();
- repaint(_dirtyRect);
- // Fire property change.
- firePropertyChange("selectedDates", oldSpan, dateSpan);
- }
- /**
- * Returns the current selection mode for this JXMonthView.
- *
- * @return int Selection mode.
- */
- public int getSelectionMode() {
- return _selectionMode;
- }
- /**
- * Set the selection mode for this JXMonthView.
- *
- * @throws IllegalArgumentException
- */
- public void setSelectionMode(int mode) throws IllegalArgumentException {
- if (mode != SINGLE_SELECTION && mode != MULTIPLE_SELECTION &&
- mode != WEEK_SELECTION && mode != NO_SELECTION) {
- throw new IllegalArgumentException(mode +
- " is not a valid selection mode");
- }
- _selectionMode = mode;
- }
- /**
- * An array of longs defining days that should be flagged. This array is
- * assumed to be in sorted order from least to greatest.
- */
- public void setFlaggedDates(long[] flaggedDates) {
- _flaggedDates = flaggedDates;
- if (_flaggedDates == null) {
- repaint();
- return;
- }
- // Loop through the flaggedDates and set the hour, minute, seconds and
- // milliseconds to 0 so we can compare times later.
- for (int i = 0; i < _flaggedDates.length; i++) {
- _cal.setTimeInMillis(_flaggedDates[i]);
- // We only want to compare the day, month and year
- // so reset all other values to 0.
- _cal.set(Calendar.HOUR_OF_DAY, 0);
- _cal.set(Calendar.MINUTE, 0);
- _cal.set(Calendar.SECOND, 0);
- _cal.set(Calendar.MILLISECOND, 0);
- _flaggedDates[i] = _cal.getTimeInMillis();
- }
- // Restore the time.
- _cal.setTimeInMillis(_firstDisplayedDate);
- repaint();
- }
- /**
- * Returns the padding used between days in the calendar.
- */
- public int getBoxPaddingX() {
- return _boxPaddingX;
- }
- /**
- * Sets the number of pixels used to pad the left and right side of a day.
- * The padding is applied to both sides of the days. Therefore, if you
- * used the padding value of 3, the number of pixels between any two days
- * would be 6.
- */
- public void setBoxPaddingX(int _boxPaddingX) {
- this._boxPaddingX = _boxPaddingX;
- _dirty = true;
- }
- /**
- * Returns the padding used above and below days in the calendar.
- */
- public int getBoxPaddingY() {
- return _boxPaddingY;
- }
- /**
- * Sets the number of pixels used to pad the top and bottom of a day.
- * The padding is applied to both the top and bottom of a day. Therefore,
- * if you used the padding value of 3, the number of pixels between any
- * two days would be 6.
- */
- public void setBoxPaddingY(int _boxPaddingY) {
- this._boxPaddingY = _boxPaddingY;
- _dirty = true;
- }
- /**
- * Returns whether or not the month view supports traversing months.
- *
- * @return <code>true</code> if month traversing is enabled.
- */
- public boolean getTraversable() {
- return _traversable;
- }
- /**
- * Set whether or not the month view will display buttons to allow the
- * user to traverse to previous or next months.
- *
- * @param traversable set to true to enable month traversing,
- * false otherwise.
- */
- public void setTraversable(boolean traversable) {
- _traversable = traversable;
- _dirty = true;
- repaint();
- }
- /**
- * Sets the single character representation for each day of the
- * week. For this method the first days of the week days[0] is assumed to
- * be <code>Calendar.SUNDAY</code>.
- *
- * @throws IllegalArgumentException if <code>days.length</code> != DAYS_IN_WEEK
- * @throws NullPointerException if <code>days</code> == null
- */
- public void setDaysOfTheWeek(String[] days)
- throws IllegalArgumentException, NullPointerException {
- if (days == null) {
- throw new NullPointerException("Array of days is null.");
- } else if (days.length != DAYS_IN_WEEK) {
- throw new IllegalArgumentException(
- "Array of days is not of length " + DAYS_IN_WEEK + " as expected.");
- }
- // TODO: This could throw off internal size information we should
- // call update and then recalculate displayed calendars and start
- // positions.
- _daysOfTheWeek = days;
- _dirty = true;
- repaint();
- }
- /**
- * Returns the single character representation for each day of the
- * week.
- *
- * @return Single character representation for the days of the week
- */
- public String[] getDaysOfTheWeek() {
- String[] days = new String[DAYS_IN_WEEK];
- System.arraycopy(_daysOfTheWeek, 0, days, 0, DAYS_IN_WEEK);
- return days;
- }
- /**
- * Gets what the first day of the week is; e.g.,
- * <code>Calendar.SUNDAY</code> in the U.S., <code>Calendar.MONDAY</code>
- * in France.
- *
- * @return int The first day of the week.
- */
- public int getFirstDayOfWeek() {
- return _firstDayOfWeek;
- }
- /**
- * Sets what the first day of the week is; e.g.,
- * <code>Calendar.SUNDAY</code> in US, <code>Calendar.MONDAY</code>
- * in France.
- *
- * @param firstDayOfWeek The first day of the week.
- *
- * @see java.util.Calendar
- */
- public void setFirstDayOfWeek(int firstDayOfWeek) {
- if (firstDayOfWeek == _firstDayOfWeek) {
- return;
- }
- _firstDayOfWeek = firstDayOfWeek;
- _cal.setFirstDayOfWeek(_firstDayOfWeek);
- repaint();
- }
- /**
- * Gets the time zone.
- *
- * @return The <code>TimeZone</code> used by the <code>JXMonthView</code>.
- */
- public TimeZone getTimeZone() {
- return _cal.getTimeZone();
- }
- /**
- * Sets the time zone with the given time zone value.
- *
- * @param tz The <code>TimeZone</code>.
- */
- public void setTimeZone(TimeZone tz) {
- _cal.setTimeZone(tz);
- }
- /**
- * Returns true if anti-aliased text is enabled for this component, false
- * otherwise.
- *
- * @return boolean <code>true</code> if anti-aliased text is enabled,
- * <code>false</code> otherwise.
- */
- public boolean getAntialiased() {
- return _antiAlias;
- }
- /**
- * Turns on/off anti-aliased text for this component.
- *
- * @param antiAlias <code>true</code> for anti-aliased text,
- * <code>false</code> to turn it off.
- */
- public void setAntialiased(boolean antiAlias) {
- if (_antiAlias == antiAlias) {
- return;
- }
- _antiAlias = antiAlias;
- repaint();
- }
- /**
- public void setDropShadowMask(int mask) {
- _dropShadowMask = mask;
- repaint();
- }
- */
- /**
- * Returns the selected background color.
- *
- * @return the selected background color.
- */
- public Color getSelectedBackground() {
- return _selectedBackground;
- }
- /**
- * Sets the selected background color to <code>c</code>. The default color
- * is <code>138, 173, 209 (Blue-ish)</code>
- *
- * @param c Selected background.
- */
- public void setSelectedBackground(Color c) {
- _selectedBackground = c;
- }
- /**
- * Returns the color used when painting the today background.
- *
- * @return Color Color
- */
- public Color getTodayBackground() {
- return _todayBackgroundColor;
- }
- /**
- * Sets the color used to draw the bounding box around today. The default
- * is the background of the <code>JXMonthView</code> component.
- *
- * @param c color to set
- */
- public void setTodayBackground(Color c) {
- _todayBackgroundColor = c;
- repaint();
- }
- /**
- * Returns the color used to paint the month string background.
- *
- * @return Color Color.
- */
- public Color getMonthStringBackground() {
- return _monthStringBackground;
- }
- /**
- * Sets the color used to draw the background of the month string. The
- * default is <code>138, 173, 209 (Blue-ish)</code>.
- *
- * @param c color to set
- */
- public void setMonthStringBackground(Color c) {
- _monthStringBackground = c;
- repaint();
- }
- /**
- * Returns the color used to paint the month string foreground.
- *
- * @return Color Color.
- */
- public Color getMonthStringForeground() {
- return _monthStringForeground;
- }
- /**
- * Sets the color used to draw the foreground of the month string. The
- * default is <code>Color.WHITE</code>.
- *
- * @param c color to set
- */
- public void setMonthStringForeground(Color c) {
- _monthStringForeground = c;
- repaint();
- }
- /**
- * Sets the color used to draw the foreground of each day of the week. These
- * are the titles
- *
- * @param c color to set
- */
- public void setDaysOfTheWeekForeground(Color c) {
- _daysOfTheWeekForeground = c;
- repaint();
- }
- /**
- * @return Color Color
- */
- public Color getDaysOfTheWeekForeground() {
- return _daysOfTheWeekForeground;
- }
- /**
- * Set the color to be used for painting the specified day of the week.
- * Acceptable values are Calendar.SUNDAY - Calendar.SATURDAY.
- *
- * @param dayOfWeek constant value defining the day of the week.
- * @param c The color to be used for painting the numeric day of the week.
- */
- public void setDayForeground(int dayOfWeek, Color c) {
- _dayToColorTable.put(dayOfWeek, c);
- }
- /**
- * Return the color that should be used for painting the numerical day of the week.
- *
- * @param dayOfWeek The day of week to get the color for.
- * @return The color to be used for painting the numeric day of the week.
- * If this was no color has yet been defined the component foreground color
- * will be returned.
- */
- public Color getDayForeground(int dayOfWeek) {
- Color c;
- c = (Color)_dayToColorTable.get(dayOfWeek);
- if (c == null) {
- c = getForeground();
- }
- return c;
- }
- /**
- * Returns a copy of the insets used to paint the month string background.
- *
- * @return Insets Month string insets.
- */
- public Insets getMonthStringInsets() {
- return (Insets)_monthStringInsets.clone();
- }
- /**
- * Insets used to modify the width/height when painting the background
- * of the month string area.
- *
- * @param insets Insets
- */
- public void setMonthStringInsets(Insets insets) {
- if (insets == null) {
- _monthStringInsets.top = 0;
- _monthStringInsets.left = 0;
- _monthStringInsets.bottom = 0;
- _monthStringInsets.right = 0;
- } else {
- _monthStringInsets.top = insets.top;
- _monthStringInsets.left = insets.left;
- _monthStringInsets.bottom = insets.bottom;
- _monthStringInsets.right = insets.right;
- }
- repaint();
- }
- /**
- * Returns the preferred number of columns to paint calendars in.
- *
- * @return int Columns of calendars.
- */
- public int getPreferredCols() {
- return _minCalCols;
- }
- /**
- * The preferred number of columns to paint calendars.
- *
- * @param cols The number of columns of calendars.
- */
- public void setPreferredCols(int cols) {
- if (cols <= 0) {
- return;
- }
- _minCalCols = cols;
- _dirty = true;
- revalidate();
- repaint();
- }
- /**
- * Returns the preferred number of rows to paint calendars in.
- *
- * @return int Rows of calendars.
- */
- public int getPreferredRows() {
- return _minCalRows;
- }
- /**
- * Sets the preferred number of rows to paint calendars.
- *
- * @param rows The number of rows of calendars.
- */
- public void setPreferredRows(int rows) {
- if (rows <= 0) {
- return;
- }
- _minCalRows = rows;
- _dirty = true;
- revalidate();
- repaint();
- }
- private void updateIfNecessary() {
- if (_dirty) {
- update();
- _dirty = false;
- }
- }
- /**
- * Calculates size information necessary for laying out the month view.
- */
- private void update() {
- // Loop through year and get largest representation of the month.
- // Keep track of the longest month so we can loop through it to
- // determine the width of a date box.
- int currDays;
- int longestMonth = 0;
- int daysInLongestMonth = 0;
- int currWidth;
- int longestMonthWidth = 0;
- // We use a bold font for figuring out size constraints since
- // it's larger and flaggedDates will be noted in this style.
- _derivedFont = getFont().deriveFont(Font.BOLD);
- FontMetrics fm = getFontMetrics(_derivedFont);
- _cal.set(Calendar.MONTH, _cal.getMinimum(Calendar.MONTH));
- _cal.set(Calendar.DAY_OF_MONTH,
- _cal.getActualMinimum(Calendar.DAY_OF_MONTH));
- for (int i = 0; i < _cal.getMaximum(Calendar.MONTH); i++) {
- currWidth = fm.stringWidth(_monthsOfTheYear[i]);
- if (currWidth > longestMonthWidth) {
- longestMonthWidth = currWidth;
- }
- currDays = _cal.getActualMaximum(Calendar.DAY_OF_MONTH);
- if (currDays > daysInLongestMonth) {
- longestMonth = _cal.get(Calendar.MONTH);
- daysInLongestMonth = currDays;
- }
- _cal.add(Calendar.MONTH, 1);
- }
- // Loop through the days of the week and adjust the box width
- // accordingly.
- _boxHeight = fm.getHeight();
- for (String dayOfTheWeek : _daysOfTheWeek) {
- currWidth = fm.stringWidth(dayOfTheWeek);
- if (currWidth > _boxWidth) {
- _boxWidth = currWidth;
- }
- }
- // Loop through longest month and get largest representation of the day
- // of the month.
- _cal.set(Calendar.MONTH, longestMonth);
- _cal.set(Calendar.DAY_OF_MONTH,
- _cal.getActualMinimum(Calendar.DAY_OF_MONTH));
- for (int i = 0; i < daysInLongestMonth; i++) {
- currWidth = fm.stringWidth(
- _dayOfMonthFormatter.format(_cal.getTime()));
- if (currWidth > _boxWidth) {
- _boxWidth = currWidth;
- }
- _cal.add(Calendar.DAY_OF_MONTH, 1);
- }
- // If the calendar is traversable, check the icon heights and
- // adjust the month box height accordingly.
- _monthBoxHeight = _boxHeight;
- if (_traversable) {
- int newHeight = _monthDownImage.getIconHeight() +
- _arrowPaddingY + _arrowPaddingY;
- if (newHeight > _monthBoxHeight) {
- _monthBoxHeight = newHeight;
- }
- }
- // Modify _boxWidth if month string is longer
- _dim.width = (_boxWidth + (2 * _boxPaddingX)) * DAYS_IN_WEEK;
- if (_dim.width < longestMonthWidth) {
- double diff = longestMonthWidth - _dim.width;
- if (_traversable) {
- diff += _monthDownImage.getIconWidth() +
- _monthUpImage.getIconWidth() + (_arrowPaddingX * 4);
- }
- _boxWidth += Math.ceil(diff / (double)DAYS_IN_WEEK);
- _dim.width = (_boxWidth + (2 * _boxPaddingX)) * DAYS_IN_WEEK;
- }
- // Keep track of calendar width and height for use later.
- _calendarWidth = (_boxWidth + (2 * _boxPaddingX)) * DAYS_IN_WEEK;
- _calendarHeight = ((_boxPaddingY + _boxHeight + _boxPaddingY) * 7) +
- (_boxPaddingY + _monthBoxHeight + _boxPaddingY);
- // Calculate minimum width/height for the component.
- _dim.height = (_calendarHeight * _minCalRows) +
- (CALENDAR_SPACING * (_minCalRows - 1));
- _dim.width = (_calendarWidth * _minCalCols) +
- (CALENDAR_SPACING * (_minCalCols - 1));
- // Add insets to the dimensions.
- Insets insets = getInsets();
- _dim.width += insets.left + insets.right;
- _dim.height += insets.top + insets.bottom;
- // Restore calendar.
- _cal.setTimeInMillis(_firstDisplayedDate);
- calculateNumDisplayedCals();
- calculateStartPosition();
- if (_startSelectedDate != -1 || _endSelectedDate != -1) {
- if (_startSelectedDate > _lastDisplayedDate ||
- _startSelectedDate < _firstDisplayedDate) {
- // Already does the recalculation for the dirty rect.
- ensureDateVisible(_startSelectedDate);
- } else {
- calculateDirtyRectForSelection();
- }
- }
- }
- private void updateToday() {
- // Update _today.
- _cal.setTimeInMillis(_today);
- _cal.add(Calendar.DAY_OF_MONTH, 1);
- _today = _cal.getTimeInMillis();
- // Restore calendar.
- _cal.setTimeInMillis(_firstDisplayedDate);
- repaint();
- }
- /**
- * Returns the minimum size needed to display this component.
- *
- * @return Dimension Minimum size.
- */
- @Override
- public Dimension getMinimumSize() {
- return getPreferredSize();
- }
- /**
- * Returns the preferred size of this component.
- *
- * @return Dimension Preferred size.
- */
- @Override
- public Dimension getPreferredSize() {
- updateIfNecessary();
- return new Dimension(_dim);
- }
- /**
- * Returns the maximum size of this component.
- *
- * @return Dimension Maximum size.
- */
- @Override
- public Dimension getMaximumSize() {
- return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
- }
- /**
- * Sets the border of this component. The Border object is responsible
- * for defining the insets for the component (overriding any insets set
- * directly on the component) and for optionally rendering any border
- * decorations within the bounds of those insets. Borders should be used
- * (rather than insets) for creating both decorative and non-decorative
- * (such as margins and padding) regions for a swing component. Compound
- * borders can be used to nest multiple borders within a single component.
- * <p>
- * As the border may modify the bounds of the component, setting the border
- * may result in a reduced number of displayed calendars.
- *
- * @param border Border.
- */
- @Override
- public void setBorder(Border border) {
- super.setBorder(border);
- _dirty = true;
- }
- /**
- * Moves and resizes this component. The new location of the top-left
- * corner is specified by x and y, and the new size is specified by
- * width and height.
- *
- * @param x The new x-coordinate of this component
- * @param y The new y-coordinate of this component
- * @param width The new width of this component
- * @param height The new height of this component
- */
- @Override
- public void setBounds(int x, int y, int width, int height) {
- super.setBounds(x, y, width, height);
- _dirty = true;
- }
- /**
- * Moves and resizes this component to conform to the new bounding
- * rectangle r. This component's new position is specified by r.x and
- * r.y, and its new size is specified by r.width and r.height
- *
- * @param r The new bounding rectangle for this component
- */
- @Override
- public void setBounds(Rectangle r) {
- setBounds(r.x, r.y, r.width, r.height);
- }
- /**
- * Sets the language-sensitive orientation that is to be used to order
- * the elements or text within this component. Language-sensitive
- * LayoutManager and Component subclasses will use this property to
- * determine how to lay out and draw components.
- * <p>
- * At construction time, a component's orientation is set to
- * ComponentOrientation.UNKNOWN, indicating that it has not been
- * specified explicitly. The UNKNOWN orientation behaves the same as
- * ComponentOrientation.LEFT_TO_RIGHT.
- *
- * @param o The component orientation.
- */
- @Override
- public void setComponentOrientation(ComponentOrientation o) {
- super.setComponentOrientation(o);
- _ltr = o.isLeftToRight();
- calculateStartPosition();
- calculateDirtyRectForSelection();
- }
- /**
- * Sets the font of this component.
- *
- * @param font The font to become this component's font; if this parameter
- * is null then this component will inherit the font of its parent.
- */
- @Override
- public void setFont(Font font) {
- super.setFont(font);
- _dirty = true;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void removeNotify() {
- _todayTimer.stop();
- super.removeNotify();
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void addNotify() {
- super.addNotify();
- // Setup timer to update the value of _today.
- int secondsTillTomorrow = 86400;
- if (_todayTimer == null) {
- _todayTimer = new Timer(secondsTillTomorrow * 1000,
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- updateToday();
- }
- });
- }
- // Modify the initial delay by the current time.
- _cal.setTimeInMillis(System.currentTimeMillis());
- secondsTillTomorrow = secondsTillTomorrow -
- (_cal.get(Calendar.HOUR_OF_DAY) * 3600) -
- (_cal.get(Calendar.MINUTE) * 60) -
- _cal.get(Calendar.SECOND);
- _todayTimer.setInitialDelay(secondsTillTomorrow * 1000);
- _todayTimer.start();
- // Restore calendar
- _cal.setTimeInMillis(_firstDisplayedDate);
- }
- /**
- * {@inheritDoc}
- */
- @Override
- protected void paintComponent(Graphics g) {
- Object oldAAValue = null;
- Graphics2D g2 = (g instanceof Graphics2D) ? (Graphics2D)g : null;
- if (g2 != null && _antiAlias) {
- oldAAValue = g2.getRenderingHint(
- RenderingHints.KEY_TEXT_ANTIALIASING);
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
- }
- Rectangle clip = g.getClipBounds();
- updateIfNecessary();
- if (isOpaque()) {
- g.setColor(getBackground());
- g.fillRect(clip.x, clip.y, clip.width, clip.height);
- }
- g.setColor(getForeground());
- Color shadowColor = g.getColor();
- shadowColor = new Color(shadowColor.getRed(), shadowColor.getGreen(),
- shadowColor.getBlue(), (int)(.20 * 255));
- FontMetrics fm = g.getFontMetrics();
- // Reset the calendar.
- _cal.setTimeInMillis(_firstDisplayedDate);
- // Center the calendars vertically in the available space.
- int y = _startY;
- for (int row = 0; row < _numCalRows; row++) {
- // Center the calendars horizontally in the available space.
- int x = _startX;
- int tmpX, tmpY;
- // Check if this row falls in the clip region.
- _bounds.x = 0;
- _bounds.y = _startY +
- row * (_calendarHeight + CALENDAR_SPACING);
- _bounds.width = getWidth();
- _bounds.height = _calendarHeight;
- if (!_bounds.intersects(clip)) {
- _cal.add(Calendar.MONTH, _numCalCols);
- y += _calendarHeight + CALENDAR_SPACING;
- continue;
- }
- for (int column = 0; column < _numCalCols; column++) {
- String monthName = _monthsOfTheYear[_cal.get(Calendar.MONTH)];
- monthName = monthName + " " + _cal.get(Calendar.YEAR);
- _bounds.x = (_ltr ? x : x - _calendarWidth);// + 4; //4px of padding on the left
- _bounds.y = y + _boxPaddingY;// + 4; //4px of padding on the top
- _bounds.width = _calendarWidth;// - 8; //4px of padding on both sides
- _bounds.height = _monthBoxHeight; //4px of padding on top
- if (_bounds.intersects(clip)) {
- // Paint month name background.
- paintMonthStringBackground(g, _bounds.x, _bounds.y,
- _bounds.width, _bounds.height);
- // Paint arrow buttons for traversing months if enabled.
- if (_traversable) {
- tmpX = _bounds.x + _arrowPaddingX;
- tmpY = _bounds.y + (_bounds.height -
- _monthDownImage.getIconHeight()) / 2;
- g.drawImage(_monthDownImage.getImage(),
- tmpX, tmpY, null);
- tmpX = _bounds.x + _bounds.width - _arrowPaddingX -
- _monthUpImage.getIconWidth();
- g.drawImage(_monthUpImage.getImage(), tmpX, tmpY, null);
- }
- // Paint month name.
- Font oldFont = getFont();
- FontMetrics oldFM = fm;
- g.setFont(_derivedFont);
- fm = getFontMetrics(_derivedFont);
- g.setColor(_monthStringForeground);
- tmpX = _ltr ?
- x + (_calendarWidth / 2) -
- (fm.stringWidth(monthName) / 2) :
- x - (_calendarWidth / 2) -
- (fm.stringWidth(monthName) / 2) - 1;
- tmpY = _bounds.y + ((_monthBoxHeight - _boxHeight) / 2) +
- fm.getAscent();
- if ((_dropShadowMask & MONTH_DROP_SHADOW) != 0) {
- g.setColor(shadowColor);
- g.drawString(monthName, tmpX + 1, tmpY + 1);
- g.setColor(_monthStringForeground);
- }
- g.drawString(monthName, tmpX, tmpY);
- g.setFont(oldFont);
- fm = oldFM;
- }
- g.setColor(getDaysOfTheWeekForeground());
- _bounds.x = _ltr ? x : x - _calendarWidth;
- _bounds.y = y + _boxPaddingY + _monthBoxHeight +
- _boxPaddingY + _boxPaddingY;
- _bounds.width = _calendarWidth;
- _bounds.height = _boxHeight;
- if (_bounds.intersects(clip)) {
- _cal.set(Calendar.DAY_OF_MONTH,
- _cal.getActualMinimum(Calendar.DAY_OF_MONTH));
- // Paint short representation of day of the week.
- int dayIndex = _firstDayOfWeek - 1;
- Font oldFont = g.getFont();
- FontMetrics oldFM = fm;
- g.setFont(_derivedFont);
- fm = getFontMetrics(_derivedFont);
- for (int i = 0; i < DAYS_IN_WEEK; i++) {
- tmpX = _ltr ?
- x + (i * (_boxPaddingX + _boxWidth +
- _boxPaddingX)) + _boxPaddingX +
- (_boxWidth / 2) -
- (fm.stringWidth(_daysOfTheWeek[dayIndex]) /
- 2) :
- x - (i * (_boxPaddingX + _boxWidth +
- _boxPaddingX)) - _boxPaddingX -
- (_boxWidth / 2) -
- (fm.stringWidth(_daysOfTheWeek[dayIndex]) /
- 2);
- tmpY = _bounds.y + fm.getAscent();
- if ((_dropShadowMask & WEEK_DROP_SHADOW) != 0) {
- g.setColor(shadowColor);
- g.drawString(_daysOfTheWeek[dayIndex],
- tmpX + 1, tmpY + 1);
- g.setColor(getDaysOfTheWeekForeground());
- }
- g.drawString(_daysOfTheWeek[dayIndex], tmpX, tmpY);
- dayIndex++;
- if (dayIndex == DAYS_IN_WEEK) {
- dayIndex = 0;
- }
- }
- g.setFont(oldFont);
- fm = oldFM;
- }
- // Check if the month to paint falls in the clip.
- _bounds.x = _startX +
- (_ltr ?
- column * (_calendarWidth + CALENDAR_SPACING) :
- -(column * (_calendarWidth + CALENDAR_SPACING) +
- _calendarWidth));
- _bounds.y = _startY +
- row * (_calendarHeight + CALENDAR_SPACING);
- _bounds.width = _calendarWidth;
- _bounds.height = _calendarHeight;
- // Paint the month if it intersects the clip. If we don't move
- // the calendar forward a month as it would have if paintMonth
- // was called.
- if (_bounds.intersects(clip)) {
- paintMonth(g, column, row);
- } else {
- _cal.add(Calendar.MONTH, 1);
- }
- x += _ltr ?
- _calendarWidth + CALENDAR_SPACING :
- -(_calendarWidth + CALENDAR_SPACING);
- }
- y += _calendarHeight + CALENDAR_SPACING;
- }
- // Restore the calendar.
- _cal.setTimeInMillis(_firstDisplayedDate);
- if (g2 != null && _antiAlias) {
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- oldAAValue);
- }
- }
- /**
- * Paints a month. It is assumed the calendar, _cal, is already set to the
- * first day of the month to be painted.
- *
- * @param col X (column) the calendar is displayed in.
- * @param row Y (row) the calendar is displayed in.
- * @param g Graphics object.
- */
- private void paintMonth(Graphics g, int col, int row) {
- String numericDay;
- int days = _cal.getActualMaximum(Calendar.DAY_OF_MONTH);
- FontMetrics fm = g.getFontMetrics();
- Rectangle clip = g.getClipBounds();
- long nextFlaggedDate = -1;
- int flaggedDateIndex = 0;
- if (_flaggedDates != null && _flaggedDates.length > 0) {
- nextFlaggedDate = _flaggedDates[flaggedDateIndex];
- }
- for (int i = 0; i < days; i++) {
- calculateBoundsForDay(_bounds);
- if (_bounds.intersects(clip)) {
- numericDay = _dayOfMonthFormatter.format(_cal.getTime());
- // Paint bounding box around any date that falls within the
- // selection.
- if (isSelectedDate(_cal.getTimeInMillis())) {
- // Keep track of the rectangle for the currently
- // selected date so we don't have to recalculate it
- // later when it becomes unselected. This is only
- // useful for SINGLE_SELECTION mode.
- if (_selectionMode == SINGLE_SELECTION) {
- _dirtyRect.x = _bounds.x;
- _dirtyRect.y = _bounds.y;
- _dirtyRect.width = _bounds.width;
- _dirtyRect.height = _bounds.height;
- }
- paintSelectedDayBackground(g, _bounds.x, _bounds.y,
- _bounds.width, _bounds.height);
- g.setColor(getForeground());
- }
- // Paint bounding box around today.
- if (_cal.getTimeInMillis() == _today) {
- paintTodayBackground(g, _bounds.x, _bounds.y,
- _bounds.width, _bounds.height);
- g.setColor(getForeground());
- }
- // If the appointment date is less than the current
- // calendar date increment to the next appointment.
- while (nextFlaggedDate != -1 &&
- nextFlaggedDate < _cal.getTimeInMillis()) {
- flaggedDateIndex++;
- if (flaggedDateIndex < _flaggedDates.length) {
- nextFlaggedDate = _flaggedDates[flaggedDateIndex];
- } else {
- nextFlaggedDate = -1;
- }
- }
- // Paint numeric day of the month.
- g.setColor(getDayForeground(_cal.get(Calendar.DAY_OF_WEEK)));
- if (nextFlaggedDate != -1 &&
- _cal.getTimeInMillis() == nextFlaggedDate) {
- Font oldFont = getFont();
- FontMetrics oldFM = fm;
- g.setFont(_derivedFont);
- fm = getFontMetrics(_derivedFont);
- g.drawString(numericDay,
- _ltr ?
- _bounds.x + _boxPaddingX +
- _boxWidth - fm.stringWidth(numericDay):
- _bounds.x + _boxPaddingX +
- _boxWidth - fm.stringWidth(numericDay) - 1,
- _bounds.y + _boxPaddingY + fm.getAscent());
- g.setFont(oldFont);
- fm = oldFM;
- } else {
- g.drawString(numericDay,
- _ltr ?
- _bounds.x + _boxPaddingX +
- _boxWidth - fm.stringWidth(numericDay):
- _bounds.x + _boxPaddingX +
- _boxWidth - fm.stringWidth(numericDay) - 1,
- _bounds.y + _boxPaddingY + fm.getAscent());
- }
- }
- _cal.add(Calendar.DAY_OF_MONTH, 1);
- }
- }
- /**
- * Paints the background of the month string. The bounding box for this
- * background can be modified by setting its insets via
- * setMonthStringInsets. The color of the background can be set via
- * setMonthStringBackground.
- *
- * @see #setMonthStringBackground
- * @see #setMonthStringInsets
- * @param g Graphics object to paint to.
- * @param x x-coordinate of upper left corner.
- * @param y y-coordinate of upper left corner.
- * @param width width of the bounding box.
- * @param height height of the bounding box.
- */
- protected void paintMonthStringBackground(Graphics g, int x, int y,
- int width, int height) {
- // Modify bounds by the month string insets.
- x = _ltr ? x + _monthStringInsets.left : x + _monthStringInsets.right;
- y = y + _monthStringInsets.top;
- width = width - _monthStringInsets.left - _monthStringInsets.right;
- height = height - _monthStringInsets.top - _monthStringInsets.bottom;
- Graphics2D g2 = (Graphics2D)g;
- GradientPaint gp = new GradientPaint(x, y + height, new Color(238, 238, 238), x, y, new Color(204, 204, 204));
- //paint the border
- // g.setColor(_monthStringBackground);
- g2.setPaint(gp);
- g2.fillRect(x, y, width - 1, height - 1);
- g2.setPaint(new Color(153, 153, 153));
- g2.drawRect(x, y, width - 1, height - 1);
- //TODO The right side of the rect is being clipped
- }
- /**
- * Paints the background for today. The default is a rectangle drawn in
- * using the color set by <code>setTodayBackground</code>
- *
- * @see #setTodayBackground
- * @param g Graphics object to paint to.
- * @param x x-coordinate of upper left corner.
- * @param y y-coordinate of upper left corner.
- * @param width width of bounding box for the day.
- * @param height height of bounding box for the day.
- */
- protected void paintTodayBackground(Graphics g, int x, int y, int width,
- int height) {
- // g.setColor(_todayBackgroundColor);
- // g.drawRect(x, y, width - 1, height - 1);
- //paint the gradiented border
- GradientPaint gp = new GradientPaint(x, y, new Color(91, 123, 145), x, y + height, new Color(68, 86, 98));
- Graphics2D g2 = (Graphics2D)g;
- g2.setPaint(gp);
- g2.drawRect(x, y, width - 1, height - 1);
- }
- /**
- * Paint the background for a selected day. The default is a filled
- * rectangle in the in the component's background color.
- *
- * @param g Graphics object to paint to.
- * @param x x-coordinate of upper left corner.
- * @param y y-coordinate of upper left corner.
- * @param width width of bounding box for the day.
- * @param height height of bounding box for the day.
- */
- protected void paintSelectedDayBackground(Graphics g, int x, int y,
- int width, int height) {
- g.setColor(getSelectedBackground());
- g.fillRect(x, y, width, height);
- }
- /**
- * Returns true if the specified time falls within the _startSelectedDate
- * and _endSelectedDate range.
- */
- private boolean isSelectedDate(long time) {
- return time >= _startSelectedDate && time <= _endSelectedDate;
- }
- /**
- * Calculates the _numCalCols/_numCalRows that determine the number of
- * calendars that can be displayed.
- */
- private void calculateNumDisplayedCals() {
- int oldNumCalCols = _numCalCols;
- int oldNumCalRows = _numCalRows;
- // Determine how many columns of calendars we want to paint.
- _numCalCols = 1;
- _numCalCols += (getWidth() - _calendarWidth) /
- (_calendarWidth + CALENDAR_SPACING);
- // Determine how many rows of calendars we want to paint.
- _numCalRows = 1;
- _numCalRows += (getHeight() - _calendarHeight) /
- (_calendarHeight + CALENDAR_SPACING);
- if (oldNumCalCols != _numCalCols ||
- oldNumCalRows != _numCalRows) {
- calculateLastDisplayedDate();
- }
- }
- /**
- * Calculates the _startX/_startY position for centering the calendars
- * within the available space.
- */
- private void calculateStartPosition() {
- // Calculate offset in x-axis for centering calendars.
- _startX = (getWidth() - ((_calendarWidth * _numCalCols) +
- (CALENDAR_SPACING * (_numCalCols - 1)))) / 2;
- if (!_ltr) {
- _startX = getWidth() - _startX;
- }
- // Calculate offset in y-axis for centering calendars.
- _startY = (getHeight() - ((_calendarHeight * _numCalRows) +
- (CALENDAR_SPACING * (_numCalRows - 1 )))) / 2;
- }
- /**
- * Calculate the bounding box for drawing a date. It is assumed that the
- * calendar, _cal, is already set to the date you want to find the offset
- * for.
- *
- * @param bounds Bounds of the date to draw in.
- */
- private void calculateBoundsForDay(Rectangle bounds) {
- int year = _cal.get(Calendar.YEAR);
- int month = _cal.get(Calendar.MONTH);
- int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK);
- int weekOfMonth = _cal.get(Calendar.WEEK_OF_MONTH);
- // Determine what row/column we are in.
- int diffMonths = month - _firstDisplayedMonth +
- ((year - _firstDisplayedYear) * MONTHS_IN_YEAR);
- int calRowIndex = diffMonths / _numCalCols;
- int calColIndex = diffMonths - (calRowIndex * _numCalCols);
- // Modify the index relative to the first day of the week.
- bounds.x = dayOfWeek - _firstDayOfWeek;
- if (bounds.x < 0) {
- bounds.x += DAYS_IN_WEEK;
- }
- // Offset for location of the day in the week.
- bounds.x = _ltr ?
- bounds.x * (_boxPaddingX + _boxWidth + _boxPaddingX) :
- (bounds.x + 1) * (_boxPaddingX + _boxWidth + _boxPaddingX);
- // Offset for the column the calendar is displayed in.
- bounds.x += calColIndex * (_calendarWidth + CALENDAR_SPACING);
- // Adjust by centering value.
- bounds.x = _ltr ? _startX + bounds.x : _startX - bounds.x;
- // Initial offset for Month and Days of the Week display.
- bounds.y = _boxPaddingY + _monthBoxHeight + _boxPaddingY +
- + _boxPaddingY + _boxHeight + _boxPaddingY;
- // Offset for centering and row the calendar is displayed in.
- bounds.y += _startY + calRowIndex *
- (_calendarHeight + CALENDAR_SPACING);
- // Offset for Week of the Month.
- bounds.y += (weekOfMonth - 1) *
- (_boxPaddingY + _boxHeight + _boxPaddingY);
- bounds.width = _boxPaddingX + _boxWidth + _boxPaddingX;
- bounds.height = _boxPaddingY + _boxHeight + _boxPaddingY;
- }
- /**
- * Return a long representing the date at the specified x/y position.
- * The date returned will have a valid day, month and year. Other fields
- * such as hour, minute, second and milli-second will be set to 0.
- *
- * @param x X position
- * @param y Y position
- * @return long The date, -1 if position does not contain a date.
- */
- public long getDayAt(int x, int y) {
- if (_ltr ? (_startX > x) : (_startX < x) || _startY > y) {
- return -1;
- }
- // Determine which column of calendars we're in.
- int calCol = (_ltr ? (x - _startX) : (_startX - x)) /
- (_calendarWidth + CALENDAR_SPACING);
- // Determine which row of calendars we're in.
- int calRow = (y - _startY) / (_calendarHeight + CALENDAR_SPACING);
- if (calRow > _numCalRows - 1 || calCol > _numCalCols - 1) {
- return -1;
- }
- // Determine what row (week) in the selected month we're in.
- int row = 1;
- row += (((y - _startY) -
- (calRow * (_calendarHeight + CALENDAR_SPACING))) -
- (_boxPaddingY + _monthBoxHeight + _boxPaddingY)) /
- (_boxPaddingY + _boxHeight + _boxPaddingY);
- // The first two lines in the calendar are the month and the days
- // of the week. Ignore them.
- row -= 2;
- if (row < 0 || row > 5) {
- return -1;
- }
- // Determine which column in the selected month we're in.
- int col = ((_ltr ? (x - _startX) : (_startX - x)) -
- (calCol * (_calendarWidth + CALENDAR_SPACING))) /
- (_boxPaddingX + _boxWidth + _boxPaddingX);
- if (col > DAYS_IN_WEEK - 1) {
- return -1;
- }
- // Use the first day of the month as a key point for determining the
- // date of our click.
- // The week index of the first day will always be 0.
- _cal.setTimeInMillis(_firstDisplayedDate);
- //_cal.set(Calendar.DAY_OF_MONTH, 1);
- _cal.add(Calendar.MONTH, calCol + (calRow * _numCalCols));
- int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK);
- int firstDayIndex = dayOfWeek - _firstDayOfWeek;
- if (firstDayIndex < 0) {
- firstDayIndex += DAYS_IN_WEEK;
- }
- int daysToAdd = (row * DAYS_IN_WEEK) + (col - firstDayIndex);
- if (daysToAdd < 0 || daysToAdd >
- (_cal.getActualMaximum(Calendar.DAY_OF_MONTH) - 1)) {
- return -1;
- }
- _cal.add(Calendar.DAY_OF_MONTH, daysToAdd);
- long selected = _cal.getTimeInMillis();
- // Restore the time.
- _cal.setTimeInMillis(_firstDisplayedDate);
- return selected;
- }
- /**
- * Returns an index defining which, if any, of the buttons for
- * traversing the month was pressed. This method should only be
- * called when <code>setTraversable</code> is set to true.
- *
- * @param x x position of the pointer
- * @param y y position of the pointer
- * @return MONTH_UP, MONTH_DOWN or -1 when no button is selected.
- */
- protected int getTraversableButtonAt(int x, int y) {
- if (_ltr ? (_startX > x) : (_startX < x) || _startY > y) {
- return -1;
- }
- // Determine which column of calendars we're in.
- int calCol = (_ltr ? (x - _startX) : (_startX - x)) /
- (_calendarWidth + CALENDAR_SPACING);
- // Determine which row of calendars we're in.
- int calRow = (y - _startY) / (_calendarHeight + CALENDAR_SPACING);
- if (calRow > _numCalRows - 1 || calCol > _numCalCols - 1) {
- return -1;
- }
- // See if we're in the month string area.
- y = ((y - _startY) -
- (calRow * (_calendarHeight + CALENDAR_SPACING))) - _boxPaddingY;
- if (y < _arrowPaddingY || y > (_monthBoxHeight - _arrowPaddingY)) {
- return -1;
- }
- x = ((_ltr ? (x - _startX) : (_startX - x)) -
- (calCol * (_calendarWidth + CALENDAR_SPACING)));
- if (x > _arrowPaddingX && x < (_arrowPaddingX +
- _monthDownImage.getIconWidth() + _arrowPaddingX)) {
- return MONTH_DOWN;
- }
- if (x > (_calendarWidth - _arrowPaddingX * 2 -
- _monthUpImage.getIconWidth()) &&
- x < (_calendarWidth - _arrowPaddingX)) {
- return MONTH_UP;
- }
- return -1;
- }
- private void calculateDirtyRectForSelection() {
- if (_startSelectedDate == -1 || _endSelectedDate == -1) {
- _dirtyRect.x = 0;
- _dirtyRect.y = 0;
- _dirtyRect.width = 0;
- _dirtyRect.height = 0;
- } else {
- _cal.setTimeInMillis(_startSelectedDate);
- calculateBoundsForDay(_dirtyRect);
- _cal.add(Calendar.DAY_OF_MONTH, 1);
- Rectangle tmpRect;
- while (_cal.getTimeInMillis() <= _endSelectedDate) {
- calculateBoundsForDay(_bounds);
- tmpRect = _dirtyRect.union(_bounds);
- _dirtyRect.x = tmpRect.x;
- _dirtyRect.y = tmpRect.y;
- _dirtyRect.width = tmpRect.width;
- _dirtyRect.height = tmpRect.height;
- _cal.add(Calendar.DAY_OF_MONTH, 1);
- }
- // Restore the time.
- _cal.setTimeInMillis(_firstDisplayedDate);
- }
- }
- /**
- * Returns the string currently used to identiy fired ActionEvents.
- *
- * @return String The string used for identifying ActionEvents.
- */
- public String getActionCommand() {
- return _actionCommand;
- }
- /**
- * Sets the string used to identify fired ActionEvents.
- *
- * @param actionCommand The string used for identifying ActionEvents.
- */
- public void setActionCommand(String actionCommand) {
- _actionCommand = actionCommand;
- }
- /**
- * Adds an ActionListener.
- * <p>
- * The ActionListener will receive an ActionEvent when a selection has
- * been made.
- *
- * @param l The ActionListener that is to be notified
- */
- public void addActionListener(ActionListener l) {
- listenerList.add(ActionListener.class, l);
- }
- /**
- * Removes an ActionListener.
- *
- * @param l The action listener to remove.
- */
- public void removeActionListener(ActionListener l) {
- listenerList.remove(ActionListener.class, l);
- }
- /**
- * Fires an ActionEvent to all listeners.
- */
- protected void fireActionPerformed() {
- Object[] listeners = listenerList.getListenerList();
- ActionEvent e = null;
- for (int i = listeners.length - 2; i >= 0; i -=2) {
- if (listeners[i] == ActionListener.class) {
- if (e == null) {
- e = new ActionEvent(JXMonthView.this,
- ActionEvent.ACTION_PERFORMED,
- _actionCommand);
- }
- ((ActionListener)listeners[i + 1]).actionPerformed(e);
- }
- }
- }
- /**
- * {@inheritDoc}
- */
- @Override
- protected void processMouseEvent(MouseEvent e) {
- // If we were using the keyboard we aren't anymore.
- _usingKeyboard = false;
- if (!isEnabled()) {
- return;
- }
- if (!hasFocus() && isFocusable()) {
- requestFocusInWindow();
- }
- int id = e.getID();
- // Check if one of the month traverse buttons was pushed.
- if (id == MouseEvent.MOUSE_PRESSED && _traversable) {
- int arrowType = getTraversableButtonAt(e.getX(), e.getY());
- if (arrowType == MONTH_DOWN) {
- setFirstDisplayedDate(
- DateUtils.getPreviousMonth(getFirstDisplayedDate()));
- return;
- } else if (arrowType == MONTH_UP) {
- setFirstDisplayedDate(
- DateUtils.getNextMonth(getFirstDisplayedDate()));
- return;
- }
- }
- if (_selectionMode == NO_SELECTION) {
- return;
- }
- if (id == MouseEvent.MOUSE_PRESSED) {
- long selected = getDayAt(e.getX(), e.getY());
- if (selected == -1) {
- return;
- }
- // Update the selected dates.
- _startSelectedDate = selected;
- _endSelectedDate = selected;
- if (_selectionMode == MULTIPLE_SELECTION ||
- _selectionMode == WEEK_SELECTION) {
- _pivotDate = selected;
- }
- // Determine the dirty rectangle of the new selected date so we
- // draw the bounding box around it. This dirty rect includes the
- // visual border of the selected date.
- _cal.setTimeInMillis(selected);
- calculateBoundsForDay(_bounds);
- _cal.setTimeInMillis(_firstDisplayedDate);
- // Repaint the old dirty area.
- repaint(_dirtyRect);
- // Repaint the new dirty area.
- repaint(_bounds);
- // Update the dirty area.
- _dirtyRect.x = _bounds.x;
- _dirtyRect.y = _bounds.y;
- _dirtyRect.width = _bounds.width;
- _dirtyRect.height = _bounds.height;
- // Arm so we fire action performed on mouse release.
- _asKirkWouldSay_FIRE = true;
- } else if (id == MouseEvent.MOUSE_RELEASED) {
- if (_asKirkWouldSay_FIRE) {
- fireActionPerformed();
- }
- _asKirkWouldSay_FIRE = false;
- }
- super.processMouseEvent(e);
- }
- /**
- * {@inheritDoc}
- */
- @Override
- protected void processMouseMotionEvent(MouseEvent e) {
- // If we were using the keyboard we aren't anymore.
- _usingKeyboard = false;
- if (!isEnabled() || _selectionMode == NO_SELECTION) {
- return;
- }
- int id = e.getID();
- if (id == MouseEvent.MOUSE_DRAGGED) {
- int x = e.getX();
- int y = e.getY();
- long selected = getDayAt(x, y);
- if (selected == -1) {
- return;
- }
- long oldStart = _startSelectedDate;
- long oldEnd = _endSelectedDate;
- if (_selectionMode == SINGLE_SELECTION) {
- if (selected == oldStart) {
- return;
- }
- _startSelectedDate = selected;
- _endSelectedDate = selected;
- } else {
- if (selected <= _pivotDate) {
- _startSelectedDate = selected;
- _endSelectedDate = _pivotDate;
- } else if (selected > _pivotDate) {
- _startSelectedDate = _pivotDate;
- _endSelectedDate = selected;
- }
- }
- if (_selectionMode == WEEK_SELECTION) {
- // Do we span a week.
- long start = (selected > _pivotDate) ? _pivotDate : selected;
- long end = (selected > _pivotDate) ? selected : _pivotDate;
- _cal.setTimeInMillis(start);
- int count = 1;
- while (_cal.getTimeInMillis() < end) {
- _cal.add(Calendar.DAY_OF_MONTH, 1);
- count++;
- }
- if (count > DAYS_IN_WEEK) {
- // Move the start date to the first day of the week.
- _cal.setTimeInMillis(start);
- int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK);
- int daysFromStart = dayOfWeek - _firstDayOfWeek;
- if (daysFromStart < 0) {
- daysFromStart += DAYS_IN_WEEK;
- }
- _cal.add(Calendar.DAY_OF_MONTH, -daysFromStart);
- _startSelectedDate = _cal.getTimeInMillis();
- // Move the end date to the last day of the week.
- _cal.setTimeInMillis(end);
- dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK);
- int lastDayOfWeek = _firstDayOfWeek - 1;
- if (lastDayOfWeek == 0) {
- lastDayOfWeek = Calendar.SATURDAY;
- }
- int daysTillEnd = lastDayOfWeek - dayOfWeek;
- if (daysTillEnd < 0) {
- daysTillEnd += DAYS_IN_WEEK;
- }
- _cal.add(Calendar.DAY_OF_MONTH, daysTillEnd);
- _endSelectedDate = _cal.getTimeInMillis();
- }
- }
- if (oldStart == _startSelectedDate && oldEnd == _endSelectedDate) {
- return;
- }
- // Repaint the old dirty area.
- repaint(_dirtyRect);
- // Repaint the new dirty area.
- calculateDirtyRectForSelection();
- repaint(_dirtyRect);
- // Set trigger.
- _asKirkWouldSay_FIRE = true;
- }
- super.processMouseMotionEvent(e);
- }
- /**
- * Class that supports keyboard traversal of the JXMonthView component.
- */
- private class KeyboardAction extends AbstractAction {
- public static final int ACCEPT_SELECTION = 0;
- public static final int CANCEL_SELECTION = 1;
- public static final int SELECT_PREVIOUS_DAY = 2;
- public static final int SELECT_NEXT_DAY = 3;
- public static final int SELECT_DAY_PREVIOUS_WEEK = 4;
- public static final int SELECT_DAY_NEXT_WEEK = 5;
- public static final int ADD_PREVIOUS_DAY = 6;
- public static final int ADD_NEXT_DAY = 7;
- public static final int ADD_TO_PREVIOUS_WEEK = 8;
- public static final int ADD_TO_NEXT_WEEK = 9;
- private int action;
- public KeyboardAction(int action) {
- this.action = action;
- }
- public void actionPerformed(ActionEvent ev) {
- int selectionMode = getSelectionMode();
- // TODO: Modify this to allow keyboard selection even if we don't have a previous selection.
- if (_startSelectedDate != -1 && selectionMode != NO_SELECTION) {
- if (!_usingKeyboard) {
- _originalDateSpan = getSelectedDateSpan();
- }
- if (action >= ACCEPT_SELECTION && action <= CANCEL_SELECTION && _usingKeyboard) {
- if (action == CANCEL_SELECTION) {
- // Restore the original selection.
- setSelectedDateSpan(_originalDateSpan);
- fireActionPerformed();
- } else {
- // Accept the keyboard selection.
- setSelectedDateSpan(getSelectedDateSpan());
- fireActionPerformed();
- }
- _usingKeyboard = false;
- } else if (action >= SELECT_PREVIOUS_DAY && action <= SELECT_DAY_NEXT_WEEK) {
- _usingKeyboard = true;
- traverse(action);
- } else if (selectionMode >= MULTIPLE_SELECTION &&
- action >= ADD_PREVIOUS_DAY && action <= ADD_TO_NEXT_WEEK) {
- _usingKeyboard = true;
- addToSelection(action);
- }
- }
- }
- private void traverse(int action) {
- _cal.setTimeInMillis(_startSelectedDate);
- switch (action) {
- case SELECT_PREVIOUS_DAY:
- _cal.add(Calendar.DAY_OF_MONTH, -1);
- break;
- case SELECT_NEXT_DAY:
- _cal.add(Calendar.DAY_OF_MONTH, 1);
- break;
- case SELECT_DAY_PREVIOUS_WEEK:
- _cal.add(Calendar.DAY_OF_MONTH, -DAYS_IN_WEEK);
- break;
- case SELECT_DAY_NEXT_WEEK:
- _cal.add(Calendar.DAY_OF_MONTH, DAYS_IN_WEEK);
- break;
- }
- long newStartDate = _cal.getTimeInMillis();
- if (newStartDate != _startSelectedDate) {
- setSelectedDateSpan(new DateSpan(newStartDate, newStartDate));
- ensureDateVisible(newStartDate);
- }
- // Restore the original time value.
- _cal.setTimeInMillis(_firstDisplayedDate);
- }
- /**
- * If we are in a mode that allows for range selection this method
- * will extend the currently selected range.
- *
- * NOTE: This may not be the expected behavior for the keyboard controls
- * and we ay need to update this code to act in a way that people expect.
- */
- private void addToSelection(int action) {
- long newStartDate = _startSelectedDate;
- long newEndDate = _endSelectedDate;
- boolean isForward = true;
- switch (action) {
- case ADD_PREVIOUS_DAY:
- _cal.setTimeInMillis(_startSelectedDate);
- _cal.add(Calendar.DAY_OF_MONTH, -1);
- newStartDate = _cal.getTimeInMillis();
- isForward = false;
- break;
- case ADD_NEXT_DAY:
- _cal.setTimeInMillis(_endSelectedDate);
- _cal.add(Calendar.DAY_OF_MONTH, 1);
- newEndDate = _cal.getTimeInMillis();
- break;
- case ADD_TO_PREVIOUS_WEEK:
- _cal.setTimeInMillis(_startSelectedDate);
- _cal.add(Calendar.DAY_OF_MONTH, -DAYS_IN_WEEK);
- newStartDate = _cal.getTimeInMillis();
- isForward = false;
- break;
- case ADD_TO_NEXT_WEEK:
- _cal.setTimeInMillis(_endSelectedDate);
- _cal.add(Calendar.DAY_OF_MONTH, DAYS_IN_WEEK);
- newEndDate = _cal.getTimeInMillis();
- break;
- }
- if (newStartDate != _startSelectedDate || newEndDate != _endSelectedDate) {
- setSelectedDateSpan(new DateSpan(newStartDate, newEndDate));
- ensureDateVisible(isForward ? newEndDate : newStartDate);
- }
- // Restore the original time value.
- _cal.setTimeInMillis(_firstDisplayedDate);
- }
- }
- }