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
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}