    001    /* ========================================================================
    002     * JCommon : a free general purpose class library for the Java(tm) platform
    003     * ========================================================================
    004     *
    005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
    006     *
    007     * Project Info:  http://www.jfree.org/jcommon/index.html
    008     *
    009     * This library is free software; you can redistribute it and/or modify it
    010     * under the terms of the GNU Lesser General Public License as published by
    011     * the Free Software Foundation; either version 2.1 of the License, or
    012     * (at your option) any later version.
    013     *
    014     * This library is distributed in the hope that it will be useful, but
    015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017     * License for more details.
    018     *
    019     * You should have received a copy of the GNU Lesser General Public
    020     * License along with this library; if not, write to the Free Software
    021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022     * USA.
    023     *
    024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025     * in the United States and other countries.]
    026     *
    027     * ---------------------------
    028     * SerialDateChooserPanel.java
    029     * ---------------------------
    030     * (C) Copyright 2001-2005, by Object Refinery Limited.
    031     *
    032     * Original Author:  David Gilbert (for Object Refinery Limited);
    033     * Contributor(s):   -;
    034     *
    035     * $Id: SerialDateChooserPanel.java,v 1.7 2007/11/02 17:50:36 taqua Exp $
    036     *
    037     * Changes
    038     * -------
    039     * 08-Dec-2001 : Version 1 (DG);
    040     * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
    041     *
    042     */
    043
    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    import javax.swing.BorderFactory;
    058    import javax.swing.JButton;
    059    import javax.swing.JComboBox;
    060    import javax.swing.JLabel;
    061    import javax.swing.JPanel;
    062    import javax.swing.SwingConstants;
    063
    064    import org.jfree.date.SerialDate;
    065
    066    /**
    067     * A panel that allows the user to select a date.
    068     * <P>
    069     * This class is incomplete and untested.  You should not use it yet...
    070     *
    071     * @author David Gilbert
    072     */
    073    public class SerialDateChooserPanel extends JPanel implements ActionListener {
    074
    075        /** The default background color for the selected date. */
    076        public static final Color DEFAULT_DATE_BUTTON_COLOR = Color.red;
    077
    078        /** The default background color for the current month. */
    079        public static final Color DEFAULT_MONTH_BUTTON_COLOR = Color.lightGray;
    080
    081        /** The date selected in the panel. */
    082        private SerialDate date;
    083
    084        /** The color for the selected date. */
    085        private Color dateButtonColor;
    086
    087        /** The color for dates in the current month. */
    088        private Color monthButtonColor;
    089
    090        /** The color for dates that are visible, but not in the current month. */
    091        private Color chosenOtherButtonColor = Color.darkGray;
    092
    093        /** The first day-of-the-week. */
    094        private int firstDayOfWeek = Calendar.SUNDAY;
    095
    096        /** The range used for selecting years. */
    097        private int yearSelectionRange = 20;
    098
    099        /** The font used to display the date. */
    100        private Font dateFont = new Font("SansSerif", Font.PLAIN, 10);
    101
    102        /** A combo for selecting the month. */
    103        private JComboBox monthSelector = null;
    104
    105        /** A combo for selecting the year. */
    106        private JComboBox yearSelector = null;
    107
    108        /** A button for selecting today's date. */
    109        private JButton todayButton = null;
    110
    111        /** An array of buttons used to display the days-of-the-month. */
    112        private JButton[] buttons = null;
    113
    114        /** A flag that indicates whether or not we are currently refreshing the buttons. */
    115        private boolean refreshing = false;
    116
    117        /**
    118         * Constructs a new date chooser panel, using today's date as the initial selection.
    119         */
    120        public SerialDateChooserPanel() {
    121
    122            this(SerialDate.createInstance(new Date()), false,
    123                 DEFAULT_DATE_BUTTON_COLOR,
    124                 DEFAULT_MONTH_BUTTON_COLOR);
    125
    126        }
    127
    128        /**
    129         * Constructs a new date chooser panel.
    130         *
    131         * @param date  the date.
    132         * @param controlPanel  a flag that indicates whether or not the 'today' button should
    133         *                      appear on the panel.
    134         */
    135        public SerialDateChooserPanel(final SerialDate date, final boolean controlPanel) {
    136
    137            this(date, controlPanel,
    138                 DEFAULT_DATE_BUTTON_COLOR,
    139                 DEFAULT_MONTH_BUTTON_COLOR);
    140
    141        }
    142
    143        /**
    144         * Constructs a new date chooser panel.
    145         *
    146         * @param date  the date.
    147         * @param controlPanel  the control panel.
    148         * @param dateButtonColor  the date button color.
    149         * @param monthButtonColor  the month button color.
    150         */
    151        public SerialDateChooserPanel(final SerialDate date, final boolean controlPanel,
    152                                      final Color dateButtonColor, final Color monthButtonColor) {
    153
    154            super(new BorderLayout());
    155
    156            this.date = date;
    157            this.dateButtonColor = dateButtonColor;
    158            this.monthButtonColor = monthButtonColor;
    159
    160            add(constructSelectionPanel(), BorderLayout.NORTH);
    161            add(getCalendarPanel(), BorderLayout.CENTER);
    162            if (controlPanel) {
    163                add(constructControlPanel(), BorderLayout.SOUTH);
    164            }
    165
    166        }
    167
    168        /**
    169         * Sets the date chosen in the panel.
    170         *
    171         * @param date  the new date.
    172         */
    173        public void setDate(final SerialDate date) {
    174
    175            this.date = date;
    176            this.monthSelector.setSelectedIndex(date.getMonth() - 1);
    177            refreshYearSelector();
    178            refreshButtons();
    179
    180        }
    181
    182        /**
    183         * Returns the date selected in the panel.
    184         *
    185         * @return the selected date.
    186         */
    187        public SerialDate getDate() {
    188            return this.date;
    189        }
    190
    191        /**
    192         * Handles action-events from the date panel.
    193         *
    194         * @param e information about the event that occurred.
    195         */
    196        public void actionPerformed(final ActionEvent e) {
    197
    198            if (e.getActionCommand().equals("monthSelectionChanged")) {
    199                final JComboBox c = (JComboBox) e.getSource();
    200                this.date = SerialDate.createInstance(
    201                    this.date.getDayOfMonth(), c.getSelectedIndex() + 1, this.date.getYYYY()
    202                );
    203                refreshButtons();
    204            }
    205            else if (e.getActionCommand().equals("yearSelectionChanged")) {
    206                if (!this.refreshing) {
    207                    final JComboBox c = (JComboBox) e.getSource();
    208                    final Integer y = (Integer) c.getSelectedItem();
    209                    this.date = SerialDate.createInstance(
    210                        this.date.getDayOfMonth(), this.date.getMonth(), y.intValue()
    211                    );
    212                    refreshYearSelector();
    213                    refreshButtons();
    214                }
    215            }
    216            else if (e.getActionCommand().equals("todayButtonClicked")) {
    217                setDate(SerialDate.createInstance(new Date()));
    218            }
    219            else if (e.getActionCommand().equals("dateButtonClicked")) {
    220                final JButton b = (JButton) e.getSource();
    221                final int i = Integer.parseInt(b.getName());
    222                final SerialDate first = getFirstVisibleDate();
    223                final SerialDate selected = SerialDate.addDays(i, first);
    224                setDate(selected);
    225            }
    226
    227        }
    228
    229        /**
    230         * Returns a panel of buttons, each button representing a day in the month.  This is a
    231         * sub-component of the DatePanel.
    232         *
    233         * @return the panel.
    234         */
    235        private JPanel getCalendarPanel() {
    236
    237            final JPanel panel = new JPanel(new GridLayout(7, 7));
    238            panel.add(new JLabel("Sun", SwingConstants.CENTER));
    239            panel.add(new JLabel("Mon", SwingConstants.CENTER));
    240            panel.add(new JLabel("Tue", SwingConstants.CENTER));
    241            panel.add(new JLabel("Wed", SwingConstants.CENTER));
    242            panel.add(new JLabel("Thu", SwingConstants.CENTER));
    243            panel.add(new JLabel("Fri", SwingConstants.CENTER));
    244            panel.add(new JLabel("Sat", SwingConstants.CENTER));
    245
    246            this.buttons = new JButton[42];
    247            for (int i = 0; i < 42; i++) {
    248                final JButton button = new JButton("");
    249                button.setMargin(new Insets(1, 1, 1, 1));
    250                button.setName(Integer.toString(i));
    251                button.setFont(this.dateFont);
    252                button.setFocusPainted(false);
    253                button.setActionCommand("dateButtonClicked");
    254                button.addActionListener(this);
    255                this.buttons[i] = button;
    256                panel.add(button);
    257            }
    258            return panel;
    259
    260        }
    261
    262        /**
    263         * Returns the button color according to the specified date.
    264         *
    265         * @param targetDate  the target date.
    266         *
    267         * @return the button color.
    268         */
    269        protected Color getButtonColor(final SerialDate targetDate) {
    270
    271            if (this.date.equals(this.date)) {
    272                return this.dateButtonColor;
    273            }
    274            else if (targetDate.getMonth() == this.date.getMonth()) {
    275                return this.monthButtonColor;
    276            }
    277            else {
    278                return this.chosenOtherButtonColor;
    279            }
    280
    281        }
    282
    283        /**
    284         * Returns the first date that is visible in the grid.  This should always be in the month
    285         * preceding the month of the selected date.
    286         *
    287         * @return the first visible date.
    288         */
    289        protected SerialDate getFirstVisibleDate() {
    290
    291            SerialDate result = SerialDate.createInstance(1, this.date.getMonth(), this.date.getYYYY());
    292            result = SerialDate.addDays(-1, result);
    293            while (result.getDayOfWeek() != getFirstDayOfWeek()) {
    294                result = SerialDate.addDays(-1, result);
    295            }
    296            return result;
    297
    298        }
    299
    300        /**
    301         * Returns the first day of the week (controls the labels in the date panel).
    302         *
    303         * @return the first day of the week.
    304         */
    305        private int getFirstDayOfWeek() {
    306            return this.firstDayOfWeek;
    307        }
    308
    309        /**
    310         * Update the button labels and colors to reflect date selection.
    311         */
    312        protected void refreshButtons() {
    313
    314            SerialDate current = getFirstVisibleDate();
    315            for (int i = 0; i < 42; i++) {
    316                final JButton button = this.buttons[i];
    317                button.setText(String.valueOf(current.getDayOfWeek()));
    318                button.setBackground(getButtonColor(current));
    319                current = SerialDate.addDays(1, current);
    320            }
    321
    322        }
    323
    324        /**
    325         * Changes the contents of the year selection JComboBox to reflect the chosen date and the year
    326         * range.
    327         */
    328        private void refreshYearSelector() {
    329            if (!this.refreshing) {
    330                this.refreshing = true;
    331                this.yearSelector.removeAllItems();
    332                final Vector v = getYears(this.date.getYYYY());
    333                for (Enumeration e = v.elements(); e.hasMoreElements();) {
    334                    this.yearSelector.addItem(e.nextElement());
    335                }
    336                this.yearSelector.setSelectedItem(new Integer(this.date.getYYYY()));
    337                this.refreshing = false;
    338            }
    339        }
    340
    341        /**
    342         * Returns a vector of years preceding and following the specified year.  The number of years
    343         * preceding and following is determined by the yearSelectionRange attribute.
    344         *
    345         * @param chosenYear  the current year.
    346         *
    347         * @return a vector of years.
    348         */
    349        private Vector getYears(final int chosenYear) {
    350            final Vector v = new Vector();
    351            for (int i = chosenYear - this.yearSelectionRange;
    352                i <= chosenYear + this.yearSelectionRange; i++) {
    353                v.addElement(new Integer(i));
    354            }
    355            return v;
    356        }
    357
    358        /**
    359         * Constructs a panel containing two JComboBoxes (for the month and year) and a button
    360         * (to reset the date to TODAY).
    361         *
    362         * @return the panel.
    363         */
    364        private JPanel constructSelectionPanel() {
    365            final JPanel p = new JPanel();
    366            this.monthSelector = new JComboBox(SerialDate.getMonths());
    367            this.monthSelector.addActionListener(this);
    368            this.monthSelector.setActionCommand("monthSelectionChanged");
    369            p.add(this.monthSelector);
    370
    371            this.yearSelector = new JComboBox(getYears(0));
    372            this.yearSelector.addActionListener(this);
    373            this.yearSelector.setActionCommand("yearSelectionChanged");
    374            p.add(this.yearSelector);
    375
    376            return p;
    377        }
    378
    379        /**
    380         * Returns a panel that appears at the bottom of the calendar panel - contains a button for
    381         * selecting today's date.
    382         *
    383         * @return the panel.
    384         */
    385        private JPanel constructControlPanel() {
    386
    387            final JPanel p = new JPanel();
    388            p.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
    389            this.todayButton = new JButton("Today");
    390            this.todayButton.addActionListener(this);
    391            this.todayButton.setActionCommand("todayButtonClicked");
    392            p.add(this.todayButton);
    393            return p;
    394
    395        }
    396
    397    }