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     * QuarterDateFormat.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     * $Id: QuarterDateFormat.java,v 1.3.2.3 2007/06/08 15:20:15 mungady Exp $
036     *
037     * Changes:
038     * --------
039     * 01-Mar-2005 : Version 1 (DG);
040     * 10-May-2005 : Added equals() method, and implemented Cloneable and 
041     *               Serializable (DG);
042     * ------------- JFREECHART 1.0.x ---------------------------------------------
043     * 08-Jun-2007 : Added Greek symbols, and support for reversing the date - see
044     *               patch 1577221 (DG);
045     *
046     */
047    
048    package org.jfree.chart.axis;
049    
050    import java.io.Serializable;
051    import java.text.DateFormat;
052    import java.text.FieldPosition;
053    import java.text.NumberFormat;
054    import java.text.ParsePosition;
055    import java.util.Arrays;
056    import java.util.Calendar;
057    import java.util.Date;
058    import java.util.GregorianCalendar;
059    import java.util.TimeZone;
060    
061    /**
062     * A formatter that formats dates to show the year and quarter (for example,
063     * '2004 IV' for the last quarter of 2004.
064     */
065    public class QuarterDateFormat extends DateFormat 
066                                   implements Cloneable, Serializable {
067        
068        /** For serialization. */
069        private static final long serialVersionUID = -6738465248529797176L;
070        
071        /** Symbols for regular quarters. */
072        public static final String[] REGULAR_QUARTERS = new String[] {"1", "2", 
073                "3", "4"};
074        
075        /** Symbols for roman numbered quarters. */
076        public static final String[] ROMAN_QUARTERS  = new String[] {"I", "II", 
077                "III", "IV"};
078        
079        /** 
080         * Symbols for greek numbered quarters. 
081         *
082         * @since 1.0.6
083         */
084        public static final String[] GREEK_QUARTERS = new String[] {"\u0391", 
085                "\u0392", "\u0393", "\u0394"};
086    
087        /** The strings. */
088        private String[] quarters = REGULAR_QUARTERS;
089        
090        /** A flag that controls whether the quarter or the year goes first. */
091        private boolean quarterFirst;
092        
093        /**
094         * Creates a new instance for the default time zone.
095         */
096        public QuarterDateFormat() {
097            this(TimeZone.getDefault());  
098        }
099        
100        /**
101         * Creates a new instance for the specified time zone.
102         * 
103         * @param zone  the time zone (<code>null</code> not permitted).
104         */
105        public QuarterDateFormat(TimeZone zone) {
106            this(zone, REGULAR_QUARTERS);
107        }
108        
109        /**
110         * Creates a new instance for the specified time zone.
111         * 
112         * @param zone  the time zone (<code>null</code> not permitted).
113         * @param quarterSymbols  the quarter symbols.
114         */
115        public QuarterDateFormat(TimeZone zone, String[] quarterSymbols) {
116            this(zone, quarterSymbols, false);
117        }
118        
119        /**
120         * Creates a new instance for the specified time zone.
121         * 
122         * @param zone  the time zone (<code>null</code> not permitted).
123         * @param quarterSymbols  the quarter symbols.
124         * @param quarterFirst  a flag that controls whether the quarter or the 
125         *         year is displayed first.
126         *         
127         * @since 1.0.6
128         */
129        public QuarterDateFormat(TimeZone zone, String[] quarterSymbols,
130                boolean quarterFirst) {
131            if (zone == null) {
132                throw new IllegalArgumentException("Null 'zone' argument.");   
133            }
134            this.calendar = new GregorianCalendar(zone);
135            this.quarters = quarterSymbols;
136            this.quarterFirst = quarterFirst;
137            
138            // the following is never used, but it seems that DateFormat requires
139            // it to be non-null.  It isn't well covered in the spec, refer to 
140            // bug parade 5061189 for more info.
141            this.numberFormat = NumberFormat.getNumberInstance();
142            
143        }
144        
145        /**
146         * Formats the given date.
147         * 
148         * @param date  the date.
149         * @param toAppendTo  the string buffer.
150         * @param fieldPosition  the field position.
151         * 
152         * @return The formatted date.
153         */
154        public StringBuffer format(Date date, StringBuffer toAppendTo,
155                                   FieldPosition fieldPosition) {
156            this.calendar.setTime(date);
157            int year = this.calendar.get(Calendar.YEAR);
158            int month = this.calendar.get(Calendar.MONTH);
159            int quarter = month / 3;
160            if (this.quarterFirst) {
161                toAppendTo.append(this.quarters[quarter]);
162                toAppendTo.append(" ");
163                toAppendTo.append(year);            
164            }
165            else {
166                toAppendTo.append(year);
167                toAppendTo.append(" ");
168                toAppendTo.append(this.quarters[quarter]);
169            }       
170            return toAppendTo;   
171        }
172    
173        /**
174         * Parses the given string (not implemented).
175         * 
176         * @param source  the date string.
177         * @param pos  the parse position.
178         * 
179         * @return <code>null</code>, as this method has not been implemented.
180         */
181        public Date parse(String source, ParsePosition pos) {
182            return null;   
183        }
184    
185        /**
186         * Tests this formatter for equality with an arbitrary object.
187         * 
188         * @param obj  the object (<code>null</code> permitted).
189         * 
190         * @return A boolean.
191         */
192        public boolean equals(Object obj) {
193            if (obj == this) {
194                return true;
195            }
196            if (!(obj instanceof QuarterDateFormat)) {
197                return false;
198            }
199            QuarterDateFormat that = (QuarterDateFormat) obj;
200            if (!Arrays.equals(this.quarters, that.quarters)) {
201                return false;
202            }
203            if (this.quarterFirst != that.quarterFirst) {
204                return false;
205            }
206            return super.equals(obj);
207        }
208        
209    }