// DayChooser package org.javamoney.examples.ez.money.gui.chooser; import static java.awt.event.MouseEvent.BUTTON1; import static java.awt.event.MouseEvent.MOUSE_CLICKED; import static java.awt.event.MouseEvent.MOUSE_ENTERED; import static java.awt.event.MouseEvent.MOUSE_EXITED; import static java.util.Calendar.DATE; import static java.util.Calendar.DAY_OF_MONTH; import static java.util.Calendar.DAY_OF_WEEK; import static java.util.Calendar.MONTH; import static java.util.Calendar.SUNDAY; import static java.util.Calendar.YEAR; import static javax.swing.BorderFactory.createLineBorder; import java.awt.Color; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.text.DateFormatSymbols; import java.util.GregorianCalendar; import javax.swing.JLabel; import javax.swing.SwingConstants; import javax.swing.border.Border; import javax.swing.border.MatteBorder; import org.javamoney.examples.ez.common.gui.Panel; import org.javamoney.examples.ez.common.utility.ActionSignaler; /** * This class facilitates choosing days in a month. */ public final class DayChooser extends Panel { /** * Constructs a new chooser that will initialize the days according to the * specified calendar. * * @param calendar The calendar to initialize the chooser. * @param firstDayOfWeek The weekday the chooser should start with. */ public DayChooser(GregorianCalendar calendar, int firstDayOfWeek) { setActionSignaler(new ActionSignaler()); setCalendar(calendar); getCalendar().setFirstDayOfWeek(firstDayOfWeek); createMonthDays(); buildPanel(); displayDays(); } /** * This method adds the action listener to the chooser. * * @param listener The action listener to add. */ public void addActionListener(ActionListener listener) { getActionSignaler().addListener(listener); } /** * This method returns the selected day's month. * * @return The selected day's month. */ public int getMonth() { return getCalendar().get(MONTH); } /** * This method returns the selected day. * * @return The selected day. */ public int getSelectedDay() { return getCalendar().get(DATE); } /** * This method returns the selected day's year. * * @return The selected day's year. */ public int getYear() { return getCalendar().get(YEAR); } /** * This method sets the selected day and configures the weekday given the * specified month and year. Invoking this method causes the chooser to * re-render the days. * * @param day The day to select. * @param month The month for configuring the weekday. * @param year The date's year for determining weekday. */ public void setDate(int day, int month, int year) { int max = getDaysInMonth(year, month); if(day > max) { day = max; } getCalendar().set(DATE, day); getCalendar().set(MONTH, month); getCalendar().set(YEAR, year); displayDays(); } /** * This method configures the weekday given the specified month. Invoking this * method causes the chooser to re-render the days. * * @param month The month for configuring the weekday. */ public void setMonth(int month) { setDate(getSelectedDay(), month, getYear()); } /** * This method sets the selected day. Invoking this method causes the chooser * to re-render the days. * * @param day The day to select. */ public void setSelectedDay(int day) { setDate(day, getMonth(), getYear()); } /** * This configures the weekday given the specified year. Invoking this method * causes the chooser to re-render the days. * * @param year The year for configuring the weekday. */ public void setYear(int year) { setDate(getSelectedDay(), getMonth(), year); } ////////////////////////////////////////////////////////////////////////////// // Start of private methods. ////////////////////////////////////////////////////////////////////////////// private void buildPanel() { String[] days = new DateFormatSymbols().getShortWeekdays(); int start = getCalendar().getFirstDayOfWeek(); // Build panel. setFill(GridBagConstraints.BOTH); addSpacer(0, 0, 1, 1, 1, 16); // Weekdays. for(int len = 0, col = 1; len < MAX_COLUMNS; ++len) { add(createWeekdayLabel(days[start++]), col++, 0, 1, 1, 14, 0); if(start > MAX_COLUMNS) { start = SUNDAY; // Start the week over. } } addSpacer(8, 0, 1, 1, 1, 0); // Month days. for(int len = 0, row = 1; row <= MAX_ROWS; ++row) { for(int col = 1; col <= MAX_COLUMNS; ++col, ++len) { add(getMonthDays()[len], col, row, 1, 1, 0, 14); } } } private void clearMonthDays() { for(int len = 0; len < getMonthDays().length; ++len) { getMonthDays()[len].setBackground(getBackground()); getMonthDays()[len].setBorder(BORDER_NORMAL); getMonthDays()[len].setEnabled(false); getMonthDays()[len].setForeground(getForeground()); } } private void createMonthDays() { MouseHandler listener = new MouseHandler(); itsMonthDays = new JLabel[MAX_COLUMNS * MAX_ROWS]; for(int len = 0; len < getMonthDays().length; ++len) { getMonthDays()[len] = new JLabel("", SwingConstants.CENTER); getMonthDays()[len].addMouseListener(listener); getMonthDays()[len].setOpaque(true); } } private static JLabel createWeekdayLabel(String day) { JLabel label = new JLabel(day, SwingConstants.CENTER); label.setBorder(new MatteBorder(1, 0, 1, 0, Color.GRAY)); label.setFont(label.getFont().deriveFont(Font.PLAIN)); label.setOpaque(true); return label; } private void displayDays() { int dayOfWeek = getStartingWeekdayIndex(); int max = getDaysInMonth(getYear(), getMonth()); int day = getDaysInMonth(getYear(), getMonth() - 1); int len = 0; clearMonthDays(); // Show trailing days in previous month. for(len = dayOfWeek - 1; len >= 0; --len, --day) { getMonthDays()[len].setText("" + day); } for(len = dayOfWeek, day = 1; day <= max; ++len, ++day) { getMonthDays()[len].setEnabled(true); getMonthDays()[len].setText("" + day); // If the day is the currently selected day, then highlight it. if(day == getSelectedDay()) { selectLabel(getMonthDays()[len]); } } // Fill out the rest of the calendar with days from the next month. for(day = 1; len < getMonthDays().length; ++len, ++day) { getMonthDays()[len].setText("" + day); } } private ActionSignaler getActionSignaler() { return itsActionSignaler; } private GregorianCalendar getCalendar() { return itsCalendar; } private static int getDaysInMonth(int year, int month) { return new GregorianCalendar(year, month, 1).getActualMaximum(DAY_OF_MONTH); } private JLabel[] getMonthDays() { return itsMonthDays; } private int getStartingWeekdayIndex() { int day = new GregorianCalendar(getYear(), getMonth(), 1).get(DAY_OF_WEEK); // Put day in proper array index form. day -= getCalendar().getFirstDayOfWeek(); if(day < 0) { day += 7; } return day; } private static void selectLabel(JLabel label) { label.setBackground(HIGHLIGHT_CELL_COLOR); label.setBorder(BORDER_SELECTED); label.setForeground(Color.WHITE); } private void setActionSignaler(ActionSignaler list) { itsActionSignaler = list; } private void setCalendar(GregorianCalendar calendar) { itsCalendar = new GregorianCalendar(); getCalendar().set(DATE, calendar.get(DATE)); getCalendar().set(MONTH, calendar.get(MONTH)); getCalendar().set(YEAR, calendar.get(YEAR)); } ////////////////////////////////////////////////////////////////////////////// // Start of inner classes. ////////////////////////////////////////////////////////////////////////////// private class MouseHandler extends MouseAdapter { /* * This method handles the specific mouse event. Firstly, it ignores all * events on days that are disabled or are already the selected day. If the * event is a click, then it sets that day to be the selected day. If the * event is a mouse entered or mouse exited, then it sets that day's border * for a UI effect. */ public void doMouseEvent(MouseEvent event) { JLabel label = (JLabel)event.getSource(); if(label.isEnabled() == true) { if(Integer.parseInt(label.getText()) != getSelectedDay()) { if(event.getID() == MOUSE_CLICKED && event.getButton() == BUTTON1) { getCalendar().set(DATE, Integer.valueOf(label.getText()).intValue()); displayDays(); getActionSignaler().sendSignal(DayChooser.this, ACTION_DAY_SELECTED); } else if(event.getID() == MOUSE_ENTERED) { label.setBorder(BORDER_SELECTED); } else if(event.getID() == MOUSE_EXITED) { label.setBorder(BORDER_NORMAL); } } else if(event.getClickCount() == 2) { getActionSignaler().sendSignal(DayChooser.this, ACTION_DAY_CHOSEN); } } } @Override public void mouseClicked(MouseEvent event) { doMouseEvent(event); } @Override public void mouseEntered(MouseEvent event) { doMouseEvent(event); } @Override public void mouseExited(MouseEvent event) { doMouseEvent(event); } } ////////////////////////////////////////////////////////////////////////////// // Start of class members. ////////////////////////////////////////////////////////////////////////////// private ActionSignaler itsActionSignaler; private GregorianCalendar itsCalendar; private JLabel[] itsMonthDays; private static final Border BORDER_NORMAL = createLineBorder(new Panel().getBackground()); private static final Border BORDER_SELECTED = createLineBorder(Color.BLACK); private static final Color HIGHLIGHT_CELL_COLOR = new Color(0, 51, 102); private static final int MAX_COLUMNS = 7; private static final int MAX_ROWS = 6; /** * This is an action constant that indicates a day was chosen via a double * click. */ public static final String ACTION_DAY_CHOSEN = "Day Chosen"; /** * This is an action constant that indicates a day was clicked on. */ public static final String ACTION_DAY_SELECTED = "Day Selected"; }