001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2006, 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     * AbstractXYItemLabelGenerator.java
029     * ---------------------------------
030     * (C) Copyright 2004, 2005, 2006, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * $Id: AbstractXYItemLabelGenerator.java,v 1.9.2.2 2006/01/27 12:51:21 mungady Exp $
036     *
037     * Changes
038     * -------
039     * 27-Feb-2004 : Version 1 (DG);
040     * 12-May-2004 : Moved default tool tip format to 
041     *               StandardXYToolTipGenerator (DG);
042     * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 
043     *               getYValue() (DG);
044     * 08-Oct-2004 : Modified createItemArray() method to handle null values (DG);
045     * 10-Jan-2005 : Updated createItemArray() to use x, y primitives if 
046     *               possible (DG);
047     * ------------- JFREECHART 1.0.0 --------------------------------------------
048     * 26-Jan-2006 : Minor API doc update (DG);
049     */
050    
051    package org.jfree.chart.labels;
052    
053    import java.io.Serializable;
054    import java.text.DateFormat;
055    import java.text.MessageFormat;
056    import java.text.NumberFormat;
057    import java.util.Date;
058    
059    import org.jfree.data.xy.XYDataset;
060    import org.jfree.util.ObjectUtilities;
061    
062    /**
063     * A base class for creating item label generators.
064     */
065    public class AbstractXYItemLabelGenerator implements Cloneable, Serializable {
066        
067        /** For serialization. */
068        private static final long serialVersionUID = 5869744396278660636L;
069        
070        /** The item label format string. */
071        private String formatString;
072        
073        /** A number formatter for the x value. */
074        private NumberFormat xFormat;
075        
076        /** A date formatter for the x value. */
077        private DateFormat xDateFormat;
078    
079        /** A formatter for the y value. */
080        private NumberFormat yFormat;
081    
082        /** A date formatter for the y value. */
083        private DateFormat yDateFormat;
084    
085        /** The string used to represent 'null' for the x-value. */
086        private String nullXString = "null";
087        
088        /** The string used to represent 'null' for the y-value. */
089        private String nullYString = "null";
090        
091        /**
092         * Creates an item label generator using default number formatters.
093         */
094        protected AbstractXYItemLabelGenerator() {
095            this(
096                "{2}", NumberFormat.getNumberInstance(), 
097                NumberFormat.getNumberInstance()
098            );
099        }
100    
101        /**
102         * Creates an item label generator using the specified number formatters.
103         *
104         * @param formatString  the item label format string (<code>null</code> 
105         *                      not permitted).
106         * @param xFormat  the format object for the x values (<code>null</code> 
107         *                 not permitted).
108         * @param yFormat  the format object for the y values (<code>null</code> 
109         *                 not permitted).
110         */
111        protected AbstractXYItemLabelGenerator(String formatString,
112                                               NumberFormat xFormat, 
113                                               NumberFormat yFormat) {
114    
115            if (formatString == null) {
116                throw new IllegalArgumentException("Null 'formatString' argument.");
117            }
118            if (xFormat == null) {
119                throw new IllegalArgumentException("Null 'xFormat' argument.");   
120            }
121            if (yFormat == null) {
122                throw new IllegalArgumentException("Null 'yFormat' argument.");   
123            }
124            this.formatString = formatString;
125            this.xFormat = xFormat;
126            this.yFormat = yFormat;
127    
128        }
129    
130        /**
131         * Creates an item label generator using the specified number formatters.
132         *
133         * @param formatString  the item label format string (<code>null</code> 
134         *                      not permitted).
135         * @param xFormat  the format object for the x values (<code>null</code> 
136         *                 permitted).
137         * @param yFormat  the format object for the y values (<code>null</code> 
138         *                 not permitted).
139         */
140        protected AbstractXYItemLabelGenerator(String formatString,
141                                               DateFormat xFormat, 
142                                               NumberFormat yFormat) {
143    
144            this(formatString, NumberFormat.getInstance(), yFormat);
145            this.xDateFormat = xFormat;
146        
147        }
148        
149        /**
150         * Creates an item label generator using the specified number formatters.
151         *
152         * @param formatString  the item label format string (<code>null</code> 
153         *                      not permitted).
154         * @param xFormat  the format object for the x values (<code>null</code> 
155         *                 permitted).
156         * @param yFormat  the format object for the y values (<code>null</code> 
157         *                 not permitted).
158         */
159        protected AbstractXYItemLabelGenerator(String formatString,
160                                               DateFormat xFormat, 
161                                               DateFormat yFormat) {
162    
163            this(
164                formatString, NumberFormat.getInstance(), 
165                NumberFormat.getInstance()
166            );
167            this.xDateFormat = xFormat;
168            this.yDateFormat = yFormat;
169        
170        }
171        
172        /**
173         * Returns the format string (this controls the overall structure of the 
174         * label).
175         * 
176         * @return The format string (never <code>null</code>).
177         */
178        public String getFormatString() {
179            return this.formatString;
180        }
181        
182        /**
183         * Returns the number formatter for the x-values.
184         *
185         * @return The number formatter (possibly <code>null</code>).
186         */
187        public NumberFormat getXFormat() {
188            return this.xFormat;
189        }
190    
191        /**
192         * Returns the date formatter for the x-values.
193         *
194         * @return The date formatter (possibly <code>null</code>).
195         */
196        public DateFormat getXDateFormat() {
197            return this.xDateFormat;
198        }
199    
200        /**
201         * Returns the number formatter for the y-values.
202         *
203         * @return The number formatter (possibly <code>null</code>).
204         */
205        public NumberFormat getYFormat() {
206            return this.yFormat;
207        }
208    
209        /**
210         * Returns the date formatter for the y-values.
211         *
212         * @return The date formatter (possibly <code>null</code>).
213         */
214        public DateFormat getYDateFormat() {
215            return this.yDateFormat;
216        }
217    
218        /**
219         * Generates a label string for an item in the dataset.
220         *
221         * @param dataset  the dataset (<code>null</code> not permitted).
222         * @param series  the series (zero-based index).
223         * @param item  the item (zero-based index).
224         *
225         * @return The label (possibly <code>null</code>).
226         */
227        public String generateLabelString(XYDataset dataset, int series, int item) {
228            String result = null;    
229            Object[] items = createItemArray(dataset, series, item);
230            result = MessageFormat.format(this.formatString, items);
231            return result;
232        }
233    
234        /**
235         * Creates the array of items that can be passed to the 
236         * {@link MessageFormat} class for creating labels.
237         *
238         * @param dataset  the dataset (<code>null</code> not permitted).
239         * @param series  the series (zero-based index).
240         * @param item  the item (zero-based index).
241         *
242         * @return An array of three items from the dataset formatted as
243         *         <code>String</code> objects (never <code>null</code>).
244         */
245        protected Object[] createItemArray(XYDataset dataset, int series, 
246                                           int item) {
247            Object[] result = new Object[3];
248            result[0] = dataset.getSeriesKey(series).toString();
249            
250            double x = dataset.getXValue(series, item);
251            if (Double.isNaN(x) && dataset.getX(series, item) == null) {
252                result[1] = this.nullXString;
253            }
254            else {
255                if (this.xDateFormat != null) {
256                    result[1] = this.xDateFormat.format(new Date((long) x));   
257                }
258                else {
259                    result[1] = this.xFormat.format(x);
260                }
261            }
262            
263            double y = dataset.getYValue(series, item);
264            if (Double.isNaN(y) && dataset.getY(series, item) == null) {
265                result[2] = this.nullYString;
266            }
267            else {
268                if (this.yDateFormat != null) {
269                    result[2] = this.yDateFormat.format(new Date((long) y));   
270                }
271                else {
272                    result[2] = this.yFormat.format(y);
273                }
274            }
275            return result;
276        }
277    
278        /**
279         * Tests this object for equality with an arbitrary object.
280         *
281         * @param obj  the other object (<code>null</code> permitted).
282         *
283         * @return A boolean.
284         */
285        public boolean equals(Object obj) {
286            if (obj == this) {
287                return true;
288            }
289            if (!(obj instanceof AbstractXYItemLabelGenerator)) {
290                return false;
291            }
292            AbstractXYItemLabelGenerator that = (AbstractXYItemLabelGenerator) obj;
293            if (!this.formatString.equals(that.formatString)) {
294                return false;   
295            }
296            if (!ObjectUtilities.equal(this.xFormat, that.xFormat)) {
297                return false;   
298            }
299            if (!ObjectUtilities.equal(this.xDateFormat, that.xDateFormat)) {
300                return false;   
301            }
302            if (!ObjectUtilities.equal(this.yFormat, that.yFormat)) {
303                return false;   
304            }
305            if (!ObjectUtilities.equal(this.yDateFormat, that.yDateFormat)) {
306                return false;   
307            }
308            return true;
309            
310        }
311    
312        /**
313         * Returns an independent copy of the generator.
314         * 
315         * @return A clone.
316         * 
317         * @throws CloneNotSupportedException if cloning is not supported.
318         */
319        public Object clone() throws CloneNotSupportedException {
320            
321            AbstractXYItemLabelGenerator clone 
322                = (AbstractXYItemLabelGenerator) super.clone();
323    
324            if (this.xFormat != null) {
325                clone.xFormat = (NumberFormat) this.xFormat.clone();
326            }
327            
328            if (this.yFormat != null) {
329                clone.yFormat = (NumberFormat) this.yFormat.clone();
330            }
331            
332            return clone;
333            
334        }
335        
336    }