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