001    /*
002     * $Id: JMonthChooser.java,v 1.3 2012/02/19 17:35:46 davep Exp $
003     *
004     * This file is part of McIDAS-V
005     *
006     * Copyright 2007-2012
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     */
030    package edu.wisc.ssec.mcidasv.data.dateChooser;
031    
032    import java.awt.BorderLayout;
033    import java.awt.Component;
034    import java.awt.Dimension;
035    import java.awt.Font;
036    import java.awt.event.ItemEvent;
037    import java.awt.event.ItemListener;
038    import java.text.DateFormatSymbols;
039    import java.util.Calendar;
040    import java.util.Locale;
041    
042    import javax.swing.JComboBox;
043    import javax.swing.JFrame;
044    import javax.swing.JPanel;
045    import javax.swing.JSpinner;
046    import javax.swing.JTextField;
047    import javax.swing.SpinnerNumberModel;
048    import javax.swing.UIManager;
049    import javax.swing.border.EmptyBorder;
050    import javax.swing.event.ChangeEvent;
051    import 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     */
060    public 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    }