001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2005, 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, by Object Refinery Limited and Contributors.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * $Id: MonthDateFormat.java,v 1.1.2.3 2005/10/25 20:37:34 mungady Exp $
036     *
037     * Changes:
038     * --------
039     * 10-May-2005 : Version 1 (DG);
040     *
041     */
042    
043    package org.jfree.chart.axis;
044    
045    import java.text.DateFormat;
046    import java.text.DateFormatSymbols;
047    import java.text.FieldPosition;
048    import java.text.NumberFormat;
049    import java.text.ParsePosition;
050    import java.text.SimpleDateFormat;
051    import java.util.Arrays;
052    import java.util.Calendar;
053    import java.util.Date;
054    import java.util.GregorianCalendar;
055    import java.util.Locale;
056    import java.util.TimeZone;
057    
058    import 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     */
064    public 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 <= 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 <= 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(
147                zone, locale, chars, new boolean[] {showYearForJan, false, false, 
148                false, false, false, false, false, false, false, false, false,
149                showYearForDec}, new SimpleDateFormat("yy")
150            );       
151        }
152        
153        /**
154         * Creates a new formatter.
155         * 
156         * @param zone  the time zone used to extract the month and year from dates
157         *              passed to this formatter (<code>null</code> not permitted).
158         * @param locale  the locale used to determine the month names 
159         *                (<code>null</code> not permitted).
160         * @param chars  the maximum number of characters to use from the month 
161         *               names, or zero to indicate that the entire month name 
162         *               should be used.
163         * @param showYear  an array of flags that control whether or not the
164         *                  year is displayed for a particular month.
165         * @param yearFormatter  the year formatter.
166         */
167        public MonthDateFormat(TimeZone zone, Locale locale, int chars, 
168                                   boolean[] showYear, DateFormat yearFormatter) {
169            if (locale == null) {
170                throw new IllegalArgumentException("Null 'locale' argument.");
171            }
172            DateFormatSymbols dfs = new DateFormatSymbols(locale);
173            String[] monthsFromLocale = dfs.getMonths();
174            this.months = new String[12];
175            for (int i = 0; i < 12; i++) {
176                    if (chars > 0) {
177                    months[i] = monthsFromLocale[i].substring(
178                        0, Math.min(chars, monthsFromLocale[i].length())
179                    );
180                    }
181                    else {
182                            months[i] = monthsFromLocale[i];
183                    }
184            }
185            this.calendar = new GregorianCalendar(zone);
186            this.showYear = showYear;
187            this.yearFormatter = yearFormatter; 
188            
189            // the following is never used, but it seems that DateFormat requires
190            // it to be non-null.  It isn't well covered in the spec, refer to 
191            // bug parade 5061189 for more info.
192            this.numberFormat = NumberFormat.getNumberInstance();
193        }
194    
195        /**
196         * Formats the given date.
197         * 
198         * @param date  the date.
199         * @param toAppendTo  the string buffer.
200         * @param fieldPosition  the field position.
201         * 
202         * @return The formatted date.
203         */
204        public StringBuffer format(Date date, StringBuffer toAppendTo,
205                                   FieldPosition fieldPosition) {
206            this.calendar.setTime(date);
207            int month = this.calendar.get(Calendar.MONTH);
208            toAppendTo.append(this.months[month]);
209            if (this.showYear[month]) {
210                toAppendTo.append(this.yearFormatter.format(date));
211            }
212            return toAppendTo;   
213        }
214    
215        /**
216         * Parses the given string (not implemented).
217         * 
218         * @param source  the date string.
219         * @param pos  the parse position.
220         * 
221         * @return <code>null</code>, as this method has not been implemented.
222         */
223        public Date parse(String source, ParsePosition pos) {
224            return null;   
225        }
226    
227        /**
228         * Tests this formatter for equality with an arbitrary object.
229         * 
230         * @param obj  the object.
231         * 
232         * @return A boolean.
233         */
234        public boolean equals(Object obj) {
235            if (obj == this) {
236                return true;
237            }
238            if (!(obj instanceof MonthDateFormat)) {
239                return false;
240            }
241            if (!super.equals(obj)) {
242                return false;
243            }
244            MonthDateFormat that = (MonthDateFormat) obj;
245            if (!Arrays.equals(this.months, that.months)) {
246                return false;
247            }
248            if (!Arrays.equals(this.showYear, that.showYear)) {
249                return false;
250            }
251            if (!this.yearFormatter.equals(that.yearFormatter)) {
252                return false;
253            }
254            return true;
255        }
256    
257        /**
258         * Some test code.
259         * 
260         * @param args  ignored.
261         */
262        public static void main(String[] args) {
263            MonthDateFormat mdf = new MonthDateFormat(Locale.UK, 2);
264            System.out.println("UK:");
265            System.out.println(mdf.format(new Month(1, 2005).getStart()));          
266            System.out.println(mdf.format(new Month(2, 2005).getStart()));          
267            System.out.println(mdf.format(new Month(3, 2005).getStart()));          
268            System.out.println(mdf.format(new Month(4, 2005).getStart()));          
269            System.out.println(mdf.format(new Month(5, 2005).getStart()));          
270            System.out.println(mdf.format(new Month(6, 2005).getStart()));          
271            System.out.println(mdf.format(new Month(7, 2005).getStart()));          
272            System.out.println(mdf.format(new Month(8, 2005).getStart()));          
273            System.out.println(mdf.format(new Month(9, 2005).getStart()));          
274            System.out.println(mdf.format(new Month(10, 2005).getStart()));         
275            System.out.println(mdf.format(new Month(11, 2005).getStart()));         
276            System.out.println(mdf.format(new Month(12, 2005).getStart()));  
277            System.out.println();
278    
279            mdf = new MonthDateFormat(Locale.GERMANY, 2);
280            System.out.println("GERMANY:");
281            System.out.println(mdf.format(new Month(1, 2005).getStart()));          
282            System.out.println(mdf.format(new Month(2, 2005).getStart()));          
283            System.out.println(mdf.format(new Month(3, 2005).getStart()));          
284            System.out.println(mdf.format(new Month(4, 2005).getStart()));          
285            System.out.println(mdf.format(new Month(5, 2005).getStart()));          
286            System.out.println(mdf.format(new Month(6, 2005).getStart()));          
287            System.out.println(mdf.format(new Month(7, 2005).getStart()));          
288            System.out.println(mdf.format(new Month(8, 2005).getStart()));          
289            System.out.println(mdf.format(new Month(9, 2005).getStart()));          
290            System.out.println(mdf.format(new Month(10, 2005).getStart()));         
291            System.out.println(mdf.format(new Month(11, 2005).getStart()));         
292            System.out.println(mdf.format(new Month(12, 2005).getStart()));  
293            System.out.println();
294            
295            mdf = new MonthDateFormat(Locale.FRANCE, 2);
296            System.out.println("FRANCE:");
297            System.out.println(mdf.format(new Month(1, 2005).getStart()));          
298            System.out.println(mdf.format(new Month(2, 2005).getStart()));          
299            System.out.println(mdf.format(new Month(3, 2005).getStart()));          
300            System.out.println(mdf.format(new Month(4, 2005).getStart()));          
301            System.out.println(mdf.format(new Month(5, 2005).getStart()));          
302            System.out.println(mdf.format(new Month(6, 2005).getStart()));          
303            System.out.println(mdf.format(new Month(7, 2005).getStart()));          
304            System.out.println(mdf.format(new Month(8, 2005).getStart()));          
305            System.out.println(mdf.format(new Month(9, 2005).getStart()));          
306            System.out.println(mdf.format(new Month(10, 2005).getStart()));         
307            System.out.println(mdf.format(new Month(11, 2005).getStart()));         
308            System.out.println(mdf.format(new Month(12, 2005).getStart()));  
309            System.out.println();
310            
311            SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
312            sdf.setNumberFormat(null);
313            System.out.println(sdf.equals("X"));
314        }
315    }