001/*
002 * $Id: JMonthChooser.java,v 1.2 2011/03/24 16:06:33 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 * 
012 * All Rights Reserved
013 * 
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.  
016 * 
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 * 
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025 * GNU Lesser Public License for more details.
026 * 
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program.  If not, see http://www.gnu.org/licenses.
029 */
030package edu.wisc.ssec.mcidasv.data.dateChooser;
031
032import java.awt.BorderLayout;
033import java.awt.Component;
034import java.awt.Dimension;
035import java.awt.Font;
036import java.awt.event.ItemEvent;
037import java.awt.event.ItemListener;
038import java.text.DateFormatSymbols;
039import java.util.Calendar;
040import java.util.Locale;
041
042import javax.swing.JComboBox;
043import javax.swing.JFrame;
044import javax.swing.JPanel;
045import javax.swing.JSpinner;
046import javax.swing.JTextField;
047import javax.swing.SpinnerNumberModel;
048import javax.swing.UIManager;
049import javax.swing.border.EmptyBorder;
050import javax.swing.event.ChangeEvent;
051import javax.swing.event.ChangeListener;
052
053/**
054 * JMonthChooser is a bean for choosing a month.
055 * 
056 * @author Kai Toedter
057 * @version $LastChangedRevision: 100 $
058 * @version $LastChangedDate: 2006-06-04 14:36:06 +0200 (So, 04 Jun 2006) $
059 */
060public class JMonthChooser extends JPanel implements ItemListener,
061                ChangeListener {
062        private static final long serialVersionUID = -2028361332231218527L;
063
064        /** true, if the month chooser has a spinner component */
065        protected boolean hasSpinner;
066
067        private Locale locale;
068
069        private int month;
070
071        private int oldSpinnerValue = 0;
072
073        // needed for comparison
074        private JDayChooser dayChooser;
075
076        private JYearChooser yearChooser;
077
078        private JComboBox comboBox;
079
080        private JSpinner spinner;
081
082        private boolean initialized;
083
084        private boolean localInitialize;
085
086        /**
087         * Default JMonthChooser constructor.
088         */
089        public JMonthChooser() {
090                this(true);
091        }
092
093        /**
094         * JMonthChooser constructor with month spinner parameter.
095         * 
096         * @param hasSpinner
097         *            true, if the month chooser should have a spinner component
098         */
099        public JMonthChooser(boolean hasSpinner) {
100                super();
101                setName("JMonthChooser");
102                this.hasSpinner = hasSpinner;
103
104                setLayout(new BorderLayout());
105
106                comboBox = new JComboBox();
107                comboBox.addItemListener(this);
108
109                // comboBox.addPopupMenuListener(this);
110                locale = Locale.getDefault();
111                initNames();
112
113                if (hasSpinner) {
114                        spinner = new JSpinner() {
115                                private static final long serialVersionUID = 1L;
116
117                                private JTextField textField = new JTextField();
118
119                                public Dimension getPreferredSize() {
120                                        Dimension size = super.getPreferredSize();
121                                        return new Dimension(size.width, textField
122                                                        .getPreferredSize().height);
123                                }
124                        };
125                        spinner.addChangeListener(this);
126                        spinner.setEditor(comboBox);
127                        comboBox.setBorder(new EmptyBorder(0, 0, 0, 0));
128                        updateUI();
129
130                        add(spinner, BorderLayout.WEST);
131                } else {
132                        add(comboBox, BorderLayout.WEST);
133                }
134
135                initialized = true;
136                setMonth(Calendar.getInstance().get(Calendar.MONTH));
137        }
138
139        /**
140         * Initializes the locale specific month names.
141         */
142        public void initNames() {
143                localInitialize = true;
144
145                DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(locale);
146                String[] monthNames = dateFormatSymbols.getMonths();
147
148                if (comboBox.getItemCount() == 12) {
149                        comboBox.removeAllItems();
150                }
151
152                for (int i = 0; i < 12; i++) {
153                        comboBox.addItem(monthNames[i]);
154                }
155
156                localInitialize = false;
157                comboBox.setSelectedIndex(month);
158        }
159
160        /**
161         * Is invoked if the state of the spnner changes.
162         * 
163         * @param e
164         *            the change event.
165         */
166        public void stateChanged(ChangeEvent e) {
167                SpinnerNumberModel model = (SpinnerNumberModel) ((JSpinner) e
168                                .getSource()).getModel();
169                int value = model.getNumber().intValue();
170                boolean increase = (value > oldSpinnerValue) ? true : false;
171                oldSpinnerValue = value;
172
173                int month = getMonth();
174
175                if (increase) {
176                        month += 1;
177
178                        if (month == 12) {
179                                month = 0;
180
181                                if (yearChooser != null) {
182                                        int year = yearChooser.getYear();
183                                        year += 1;
184                                        yearChooser.setYear(year);
185                                }
186                        }
187                } else {
188                        month -= 1;
189
190                        if (month == -1) {
191                                month = 11;
192
193                                if (yearChooser != null) {
194                                        int year = yearChooser.getYear();
195                                        year -= 1;
196                                        yearChooser.setYear(year);
197                                }
198                        }
199                }
200
201                setMonth(month);
202        }
203
204        /**
205         * The ItemListener for the months.
206         * 
207         * @param e
208         *            the item event
209         */
210        public void itemStateChanged(ItemEvent e) {
211                if (e.getStateChange() == ItemEvent.SELECTED) {
212                        int index = comboBox.getSelectedIndex();
213
214                        if ((index >= 0) && (index != month)) {
215                                setMonth(index, false);
216                        }
217                }
218        }
219
220        /**
221         * Sets the month attribute of the JMonthChooser object. Fires a property
222         * change "month".
223         * 
224         * @param newMonth
225         *            the new month value
226         * @param select
227         *            true, if the month should be selcted in the combo box.
228         */
229        private void setMonth(int newMonth, boolean select) {
230                if (!initialized || localInitialize) {
231                        return;
232                }
233
234                int oldMonth = month;
235                month = newMonth;
236
237                if (select) {
238                        comboBox.setSelectedIndex(month);
239                }
240
241                if (dayChooser != null) {
242                        dayChooser.setMonth(month);
243                }
244
245                firePropertyChange("month", oldMonth, month);
246        }
247
248        /**
249         * Sets the month. This is a bound property. Valuse are valid between 0
250         * (January) and 11 (December). A value < 0 will be treated as 0, a value >
251         * 11 will be treated as 11.
252         * 
253         * @param newMonth
254         *            the new month value
255         * 
256         * @see #getMonth
257         */
258        public void setMonth(int newMonth) {
259                if (newMonth < 0 || newMonth == Integer.MIN_VALUE) {
260                        setMonth(0, true);
261                } else if (newMonth > 11) {
262                        setMonth(11, true);
263                } else {
264                        setMonth(newMonth, true);
265                }
266        }
267
268        /**
269         * Returns the month.
270         * 
271         * @return the month value
272         */
273        public int getMonth() {
274                return month;
275        }
276
277        /**
278         * Convenience method set a day chooser.
279         * 
280         * @param dayChooser
281         *            the day chooser
282         */
283        public void setDayChooser(JDayChooser dayChooser) {
284                this.dayChooser = dayChooser;
285        }
286
287        /**
288         * Convenience method set a year chooser. If set, the spin for the month
289         * buttons will spin the year as well
290         * 
291         * @param yearChooser
292         *            the new yearChooser value
293         */
294        public void setYearChooser(JYearChooser yearChooser) {
295                this.yearChooser = yearChooser;
296        }
297
298        /**
299         * Returns the locale.
300         * 
301         * @return the locale value
302         * 
303         * @see #setLocale
304         */
305        public Locale getLocale() {
306                return locale;
307        }
308
309        /**
310         * Set the locale and initializes the new month names.
311         * 
312         * @param l
313         *            the new locale value
314         * 
315         * @see #getLocale
316         */
317        public void setLocale(Locale l) {
318                if (!initialized) {
319                        super.setLocale(l);
320                } else {
321                        locale = l;
322                        initNames();
323                }
324        }
325
326        /**
327         * Enable or disable the JMonthChooser.
328         * 
329         * @param enabled
330         *            the new enabled value
331         */
332        public void setEnabled(boolean enabled) {
333                super.setEnabled(enabled);
334                comboBox.setEnabled(enabled);
335
336                if (spinner != null) {
337                        spinner.setEnabled(enabled);
338                }
339        }
340
341        /**
342         * Returns the month chooser's comboBox text area (which allow the focus to
343         * be set to it).
344         * 
345         * @return the combo box
346         */
347        public Component getComboBox() {
348                return this.comboBox;
349        }
350
351        /**
352         * Returns the month chooser's comboBox bar (which allow the focus to be set
353         * to it).
354         * 
355         * @return Component the spinner or null, if the month chooser has no
356         *         spinner
357         */
358        public Component getSpinner() {
359                // Returns <null> if there is no spinner.
360                return spinner;
361        }
362
363        /**
364         * Returns the type of spinner the month chooser is using.
365         * 
366         * @return true, if the month chooser has a spinner
367         */
368        public boolean hasSpinner() {
369                return hasSpinner;
370        }
371
372    /**
373     * Sets the font for this component.
374     *
375     * @param font the desired <code>Font</code> for this component
376     */
377        public void setFont(Font font) {
378                if (comboBox != null) {
379                        comboBox.setFont(font);
380                }
381                super.setFont(font);
382        }
383
384        /**
385         * Updates the UI.
386         * 
387         * @see javax.swing.JPanel#updateUI()
388         */
389        public void updateUI() {
390                final JSpinner testSpinner = new JSpinner();
391                if (spinner != null) {
392                        if ("Windows".equals(UIManager.getLookAndFeel().getID())) {
393                                spinner.setBorder(testSpinner.getBorder());
394                        } else {
395                                spinner.setBorder(new EmptyBorder(0, 0, 0, 0));
396                        }
397                }
398        }
399
400        /**
401         * Creates a JFrame with a JMonthChooser inside and can be used for testing.
402         * 
403         * @param s
404         *            The command line arguments
405         */
406        public static void main(String[] s) {
407                JFrame frame = new JFrame("MonthChooser");
408                frame.getContentPane().add(new JMonthChooser());
409                frame.pack();
410                frame.setVisible(true);
411        }
412}