001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2014, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * --------------------
028 * MonthDateFormat.java
029 * --------------------
030 * (C) Copyright 2005-2014, 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 * 02-Jul-2013 : Use ParamChecks (DG);
039 *
040 */
041
042package org.jfree.chart.axis;
043
044import java.text.DateFormat;
045import java.text.DateFormatSymbols;
046import java.text.FieldPosition;
047import java.text.NumberFormat;
048import java.text.ParsePosition;
049import java.text.SimpleDateFormat;
050import java.util.Arrays;
051import java.util.Calendar;
052import java.util.Date;
053import java.util.GregorianCalendar;
054import java.util.Locale;
055import java.util.TimeZone;
056import org.jfree.chart.util.ParamChecks;
057
058import org.jfree.data.time.Month;
059
060/**
061 * A formatter that formats dates to show the initial letter(s) of the month
062 * name and, as an option, the year for the first or last month of each year.
063 */
064public class MonthDateFormat extends DateFormat {
065
066    /** The symbols used for the months. */
067    private String[] months;
068
069    /** Flags that control which months will have the year appended. */
070    private boolean[] showYear;
071
072    /** The year formatter. */
073    private DateFormat yearFormatter;
074
075    /**
076     * Creates a new instance for the default time zone.
077     */
078    public MonthDateFormat() {
079        this(TimeZone.getDefault());
080    }
081
082    /**
083     * Creates a new instance for the specified time zone.
084     *
085     * @param zone  the time zone (<code>null</code> not permitted).
086     */
087    public MonthDateFormat(TimeZone zone) {
088        this(zone, Locale.getDefault(), 1, true, false);
089    }
090
091    /**
092     * Creates a new instance for the specified time zone.
093     *
094     * @param locale  the locale used to obtain the month
095     *                names (<code>null</code> not permitted).
096     */
097    public MonthDateFormat(Locale locale) {
098        this(TimeZone.getDefault(), locale, 1, true, false);
099    }
100
101    /**
102     * Creates a new instance for the specified time zone.
103     *
104     * @param zone  the time zone (<code>null</code> not permitted).
105     * @param chars  the maximum number of characters to use from the month
106     *               names (that are obtained from the date symbols of the
107     *               default locale).  If this value is &lt;= 0, the entire
108     *               month name is used in each case.
109     */
110    public MonthDateFormat(TimeZone zone, int chars) {
111        this(zone, Locale.getDefault(), chars, true, false);
112    }
113
114    /**
115     * Creates a new instance for the specified time zone.
116     *
117     * @param locale  the locale (<code>null</code> not permitted).
118     * @param chars  the maximum number of characters to use from the month
119     *               names (that are obtained from the date symbols of the
120     *               default locale).  If this value is &lt;= 0, the entire
121     *               month name is used in each case.
122     */
123    public MonthDateFormat(Locale locale, int chars) {
124        this(TimeZone.getDefault(), locale, chars, true, false);
125    }
126
127    /**
128     * Creates a new formatter.
129     *
130     * @param zone  the time zone used to extract the month and year from dates
131     *              passed to this formatter (<code>null</code> not permitted).
132     * @param locale  the locale used to determine the month names
133     *                (<code>null</code> not permitted).
134     * @param chars  the maximum number of characters to use from the month
135     *               names, or zero to indicate that the entire month name
136     *               should be used.
137     * @param showYearForJan  a flag that controls whether or not the year is
138     *                        appended to the symbol for the first month of
139     *                        each year.
140     * @param showYearForDec  a flag that controls whether or not the year is
141     *                        appended to the symbol for the last month of
142     *                        each year.
143     */
144    public MonthDateFormat(TimeZone zone, Locale locale, int chars,
145                           boolean showYearForJan, boolean showYearForDec) {
146        this(zone, locale, chars, new boolean[] {showYearForJan, false, false,
147            false, false, false, false, false, false, false, false, false,
148            showYearForDec}, new SimpleDateFormat("yy"));
149    }
150
151    /**
152     * Creates a new formatter.
153     *
154     * @param zone  the time zone used to extract the month and year from dates
155     *              passed to this formatter (<code>null</code> not permitted).
156     * @param locale  the locale used to determine the month names
157     *                (<code>null</code> not permitted).
158     * @param chars  the maximum number of characters to use from the month
159     *               names, or zero to indicate that the entire month name
160     *               should be used.
161     * @param showYear  an array of flags that control whether or not the
162     *                  year is displayed for a particular month.
163     * @param yearFormatter  the year formatter.
164     */
165    public MonthDateFormat(TimeZone zone, Locale locale, int chars,
166                           boolean[] showYear, DateFormat yearFormatter) {
167        ParamChecks.nullNotPermitted(locale, "locale");
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    @Override
200    public StringBuffer format(Date date, StringBuffer toAppendTo,
201                               FieldPosition fieldPosition) {
202        this.calendar.setTime(date);
203        int month = this.calendar.get(Calendar.MONTH);
204        toAppendTo.append(this.months[month]);
205        if (this.showYear[month]) {
206            toAppendTo.append(this.yearFormatter.format(date));
207        }
208        return toAppendTo;
209    }
210
211    /**
212     * Parses the given string (not implemented).
213     *
214     * @param source  the date string.
215     * @param pos  the parse position.
216     *
217     * @return <code>null</code>, as this method has not been implemented.
218     */
219    @Override
220    public Date parse(String source, ParsePosition pos) {
221        return null;
222    }
223
224    /**
225     * Tests this formatter for equality with an arbitrary object.
226     *
227     * @param obj  the object.
228     *
229     * @return A boolean.
230     */
231    @Override
232    public boolean equals(Object obj) {
233        if (obj == this) {
234            return true;
235        }
236        if (!(obj instanceof MonthDateFormat)) {
237            return false;
238        }
239        if (!super.equals(obj)) {
240            return false;
241        }
242        MonthDateFormat that = (MonthDateFormat) obj;
243        if (!Arrays.equals(this.months, that.months)) {
244            return false;
245        }
246        if (!Arrays.equals(this.showYear, that.showYear)) {
247            return false;
248        }
249        if (!this.yearFormatter.equals(that.yearFormatter)) {
250            return false;
251        }
252        return true;
253    }
254}