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