001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, 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-2007, 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
041package org.jfree.chart.axis;
042
043import java.text.DateFormat;
044import java.text.DateFormatSymbols;
045import java.text.FieldPosition;
046import java.text.NumberFormat;
047import java.text.ParsePosition;
048import java.text.SimpleDateFormat;
049import java.util.Arrays;
050import java.util.Calendar;
051import java.util.Date;
052import java.util.GregorianCalendar;
053import java.util.Locale;
054import java.util.TimeZone;
055
056import 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 */
062public 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}