    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    }