001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
006     *
007     * Project Info:  http://www.jfree.org/jfreechart/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     * MonthDateFormat.java
029     * --------------------
030     * (C) Copyright 2005-2008, by Object Refinery Limited and Contributors.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * Changes:
036     * --------
037     * 10-May-2005 : Version 1 (DG);
038     *
039     */
040    
041    package org.jfree.chart.axis;
042    
043    import java.text.DateFormat;
044    import java.text.DateFormatSymbols;
045    import java.text.FieldPosition;
046    import java.text.NumberFormat;
047    import java.text.ParsePosition;
048    import java.text.SimpleDateFormat;
049    import java.util.Arrays;
050    import java.util.Calendar;
051    import java.util.Date;
052    import java.util.GregorianCalendar;
053    import java.util.Locale;
054    import java.util.TimeZone;
055    
056    import org.jfree.data.time.Month;
057    
058    /**
059     * A formatter that formats dates to show the initial letter(s) of the month
060     * name and, as an option, the year for the first or last month of each year.
061     */
062    public class MonthDateFormat extends DateFormat {
063    
064        /** The symbols used for the months. */
065        private String[] months;
066    
067        /** Flags that control which months will have the year appended. */
068        private boolean[] showYear;
069    
070        /** The year formatter. */
071        private DateFormat yearFormatter;
072    
073        /**
074         * Creates a new instance for the default time zone.
075         */
076        public MonthDateFormat() {
077            this(TimeZone.getDefault());
078        }
079    
080        /**
081         * Creates a new instance for the specified time zone.
082         *
083         * @param zone  the time zone (<code>null</code> not permitted).
084         */
085        public MonthDateFormat(TimeZone zone) {
086            this(zone, Locale.getDefault(), 1, true, false);
087        }
088    
089        /**
090         * Creates a new instance for the specified time zone.
091         *
092         * @param locale  the locale used to obtain the month
093         *                names (<code>null</code> not permitted).
094         */
095        public MonthDateFormat(Locale locale) {
096            this(TimeZone.getDefault(), locale, 1, true, false);
097        }
098    
099        /**
100         * Creates a new instance for the specified time zone.
101         *
102         * @param zone  the time zone (<code>null</code> not permitted).
103         * @param chars  the maximum number of characters to use from the month
104         *               names (that are obtained from the date symbols of the
105         *               default locale).  If this value is <= 0, the entire
106         *               month name is used in each case.
107         */
108        public MonthDateFormat(TimeZone zone, int chars) {
109            this(zone, Locale.getDefault(), chars, true, false);
110        }
111    
112        /**
113         * Creates a new instance for the specified time zone.
114         *
115         * @param locale  the locale (<code>null</code> not permitted).
116         * @param chars  the maximum number of characters to use from the month
117         *               names (that are obtained from the date symbols of the
118         *               default locale).  If this value is <= 0, the entire
119         *               month name is used in each case.
120         */
121        public MonthDateFormat(Locale locale, int chars) {
122            this(TimeZone.getDefault(), locale, chars, true, false);
123        }
124    
125        /**
126         * Creates a new formatter.
127         *
128         * @param zone  the time zone used to extract the month and year from dates
129         *              passed to this formatter (<code>null</code> not permitted).
130         * @param locale  the locale used to determine the month names
131         *                (<code>null</code> not permitted).
132         * @param chars  the maximum number of characters to use from the month
133         *               names, or zero to indicate that the entire month name
134         *               should be used.
135         * @param showYearForJan  a flag that controls whether or not the year is
136         *                        appended to the symbol for the first month of
137         *                        each year.
138         * @param showYearForDec  a flag that controls whether or not the year is
139         *                        appended to the symbol for the last month of
140         *                        each year.
141         */
142        public MonthDateFormat(TimeZone zone, Locale locale, int chars,
143                               boolean showYearForJan, boolean showYearForDec) {
144            this(zone, locale, chars, new boolean[] {showYearForJan, false, false,
145                false, false, false, false, false, false, false, false, false,
146                showYearForDec}, new SimpleDateFormat("yy"));
147        }
148    
149        /**
150         * Creates a new formatter.
151         *
152         * @param zone  the time zone used to extract the month and year from dates
153         *              passed to this formatter (<code>null</code> not permitted).
154         * @param locale  the locale used to determine the month names
155         *                (<code>null</code> not permitted).
156         * @param chars  the maximum number of characters to use from the month
157         *               names, or zero to indicate that the entire month name
158         *               should be used.
159         * @param showYear  an array of flags that control whether or not the
160         *                  year is displayed for a particular month.
161         * @param yearFormatter  the year formatter.
162         */
163        public MonthDateFormat(TimeZone zone, Locale locale, int chars,
164                               boolean[] showYear, DateFormat yearFormatter) {
165            if (locale == null) {
166                throw new IllegalArgumentException("Null 'locale' argument.");
167            }
168            DateFormatSymbols dfs = new DateFormatSymbols(locale);
169            String[] monthsFromLocale = dfs.getMonths();
170            this.months = new String[12];
171            for (int i = 0; i < 12; i++) {
172                if (chars > 0) {
173                    this.months[i] = monthsFromLocale[i].substring(0,
174                            Math.min(chars, monthsFromLocale[i].length()));
175                }
176                else {
177                    this.months[i] = monthsFromLocale[i];
178                }
179            }
180            this.calendar = new GregorianCalendar(zone);
181            this.showYear = showYear;
182            this.yearFormatter = yearFormatter;
183    
184            // the following is never used, but it seems that DateFormat requires
185            // it to be non-null.  It isn't well covered in the spec, refer to
186            // bug parade 5061189 for more info.
187            this.numberFormat = NumberFormat.getNumberInstance();
188        }
189    
190        /**
191         * Formats the given date.
192         *
193         * @param date  the date.
194         * @param toAppendTo  the string buffer.
195         * @param fieldPosition  the field position.
196         *
197         * @return The formatted date.
198         */
199        public StringBuffer format(Date date, StringBuffer toAppendTo,
200                                   FieldPosition fieldPosition) {
201            this.calendar.setTime(date);
202            int month = this.calendar.get(Calendar.MONTH);
203            toAppendTo.append(this.months[month]);
204            if (this.showYear[month]) {
205                toAppendTo.append(this.yearFormatter.format(date));
206            }
207            return toAppendTo;
208        }
209    
210        /**
211         * Parses the given string (not implemented).
212         *
213         * @param source  the date string.
214         * @param pos  the parse position.
215         *
216         * @return <code>null</code>, as this method has not been implemented.
217         */
218        public Date parse(String source, ParsePosition pos) {
219            return null;
220        }
221    
222        /**
223         * Tests this formatter for equality with an arbitrary object.
224         *
225         * @param obj  the object.
226         *
227         * @return A boolean.
228         */
229        public boolean equals(Object obj) {
230            if (obj == this) {
231                return true;
232            }
233            if (!(obj instanceof MonthDateFormat)) {
234                return false;
235            }
236            if (!super.equals(obj)) {
237                return false;
238            }
239            MonthDateFormat that = (MonthDateFormat) obj;
240            if (!Arrays.equals(this.months, that.months)) {
241                return false;
242            }
243            if (!Arrays.equals(this.showYear, that.showYear)) {
244                return false;
245            }
246            if (!this.yearFormatter.equals(that.yearFormatter)) {
247                return false;
248            }
249            return true;
250        }
251    
252        /**
253         * Some test code.
254         *
255         * @param args  ignored.
256         */
257        public static void main(String[] args) {
258            MonthDateFormat mdf = new MonthDateFormat(Locale.UK, 2);
259            System.out.println("UK:");
260            System.out.println(mdf.format(new Month(1, 2005).getStart()));
261            System.out.println(mdf.format(new Month(2, 2005).getStart()));
262            System.out.println(mdf.format(new Month(3, 2005).getStart()));
263            System.out.println(mdf.format(new Month(4, 2005).getStart()));
264            System.out.println(mdf.format(new Month(5, 2005).getStart()));
265            System.out.println(mdf.format(new Month(6, 2005).getStart()));
266            System.out.println(mdf.format(new Month(7, 2005).getStart()));
267            System.out.println(mdf.format(new Month(8, 2005).getStart()));
268            System.out.println(mdf.format(new Month(9, 2005).getStart()));
269            System.out.println(mdf.format(new Month(10, 2005).getStart()));
270            System.out.println(mdf.format(new Month(11, 2005).getStart()));
271            System.out.println(mdf.format(new Month(12, 2005).getStart()));
272            System.out.println();
273    
274            mdf = new MonthDateFormat(Locale.GERMANY, 2);
275            System.out.println("GERMANY:");
276            System.out.println(mdf.format(new Month(1, 2005).getStart()));
277            System.out.println(mdf.format(new Month(2, 2005).getStart()));
278            System.out.println(mdf.format(new Month(3, 2005).getStart()));
279            System.out.println(mdf.format(new Month(4, 2005).getStart()));
280            System.out.println(mdf.format(new Month(5, 2005).getStart()));
281            System.out.println(mdf.format(new Month(6, 2005).getStart()));
282            System.out.println(mdf.format(new Month(7, 2005).getStart()));
283            System.out.println(mdf.format(new Month(8, 2005).getStart()));
284            System.out.println(mdf.format(new Month(9, 2005).getStart()));
285            System.out.println(mdf.format(new Month(10, 2005).getStart()));
286            System.out.println(mdf.format(new Month(11, 2005).getStart()));
287            System.out.println(mdf.format(new Month(12, 2005).getStart()));
288            System.out.println();
289    
290            mdf = new MonthDateFormat(Locale.FRANCE, 2);
291            System.out.println("FRANCE:");
292            System.out.println(mdf.format(new Month(1, 2005).getStart()));
293            System.out.println(mdf.format(new Month(2, 2005).getStart()));
294            System.out.println(mdf.format(new Month(3, 2005).getStart()));
295            System.out.println(mdf.format(new Month(4, 2005).getStart()));
296            System.out.println(mdf.format(new Month(5, 2005).getStart()));
297            System.out.println(mdf.format(new Month(6, 2005).getStart()));
298            System.out.println(mdf.format(new Month(7, 2005).getStart()));
299            System.out.println(mdf.format(new Month(8, 2005).getStart()));
300            System.out.println(mdf.format(new Month(9, 2005).getStart()));
301            System.out.println(mdf.format(new Month(10, 2005).getStart()));
302            System.out.println(mdf.format(new Month(11, 2005).getStart()));
303            System.out.println(mdf.format(new Month(12, 2005).getStart()));
304            System.out.println();
305    
306            SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
307            sdf.setNumberFormat(null);
308        }
309    }