    001/* ===========================================================
    002 * JFreeChart : a free chart library for the Java(tm) platform
    003 * ===========================================================
    004 *
    005 * (C) Copyright 2000-2011, 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 * AbstractXYItemLabelGenerator.java
    029 * ---------------------------------
    030 * (C) Copyright 2004-2008, by Object Refinery Limited.
    031 *
    032 * Original Author:  David Gilbert (for Object Refinery Limited);
    033 * Contributor(s):   -;
    034 *
    035 * Changes
    036 * -------
    037 * 27-Feb-2004 : Version 1 (DG);
    038 * 12-May-2004 : Moved default tool tip format to
    039 *               StandardXYToolTipGenerator (DG);
    040 * 15-Jul-2004 : Switched getX() with getXValue() and getY() with
    041 *               getYValue() (DG);
    042 * 08-Oct-2004 : Modified createItemArray() method to handle null values (DG);
    043 * 10-Jan-2005 : Updated createItemArray() to use x, y primitives if
    044 *               possible (DG);
    045 * ------------- JFREECHART 1.0.x --------------------------------------------
    046 * 26-Jan-2006 : Minor API doc update (DG);
    047 * 25-Jan-2007 : Added new constructor and fixed bug in clone() method (DG);
    048 * 16-Oct-2007 : Removed redundant code (DG);
    049 * 23-Nov-2007 : Implemented hashCode() (DG);
    050 * 26-May-2008 : Added accessor methods for nullYString and updated equals()
    051 *               method (DG);
    052 *
    053 */
    054
    055package org.jfree.chart.labels;
    056
    057import java.io.Serializable;
    058import java.text.DateFormat;
    059import java.text.MessageFormat;
    060import java.text.NumberFormat;
    061import java.util.Date;
    062
    063import org.jfree.chart.HashUtilities;
    064import org.jfree.data.xy.XYDataset;
    065import org.jfree.util.ObjectUtilities;
    066
    067/**
    068 * A base class for creating item label generators.
    069 */
    070public class AbstractXYItemLabelGenerator implements Cloneable, Serializable {
    071
    072    /** For serialization. */
    073    private static final long serialVersionUID = 5869744396278660636L;
    074
    075    /** The item label format string. */
    076    private String formatString;
    077
    078    /** A number formatter for the x value. */
    079    private NumberFormat xFormat;
    080
    081    /** A date formatter for the x value. */
    082    private DateFormat xDateFormat;
    083
    084    /** A formatter for the y value. */
    085    private NumberFormat yFormat;
    086
    087    /** A date formatter for the y value. */
    088    private DateFormat yDateFormat;
    089
    090    /** The string used to represent 'null' for the y-value. */
    091    private String nullYString = "null";
    092
    093    /**
    094     * Creates an item label generator using default number formatters.
    095     */
    096    protected AbstractXYItemLabelGenerator() {
    097        this("{2}", NumberFormat.getNumberInstance(),
    098                NumberFormat.getNumberInstance());
    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 formatters (a
    151     * number formatter for the x-values and a date formatter for the
    152     * y-values).
    153     *
    154     * @param formatString  the item label format string (<code>null</code>
    155     *                      not permitted).
    156     * @param xFormat  the format object for the x values (<code>null</code>
    157     *                 permitted).
    158     * @param yFormat  the format object for the y values (<code>null</code>
    159     *                 not permitted).
    160     *
    161     * @since 1.0.4
    162     */
    163    protected AbstractXYItemLabelGenerator(String formatString,
    164            NumberFormat xFormat, DateFormat yFormat) {
    165
    166        this(formatString, xFormat, NumberFormat.getInstance());
    167        this.yDateFormat = yFormat;
    168    }
    169
    170    /**
    171     * Creates an item label generator using the specified number formatters.
    172     *
    173     * @param formatString  the item label format string (<code>null</code>
    174     *                      not permitted).
    175     * @param xFormat  the format object for the x values (<code>null</code>
    176     *                 permitted).
    177     * @param yFormat  the format object for the y values (<code>null</code>
    178     *                 not permitted).
    179     */
    180    protected AbstractXYItemLabelGenerator(String formatString,
    181                                           DateFormat xFormat,
    182                                           DateFormat yFormat) {
    183
    184        this(formatString, NumberFormat.getInstance(),
    185                NumberFormat.getInstance());
    186        this.xDateFormat = xFormat;
    187        this.yDateFormat = yFormat;
    188
    189    }
    190
    191    /**
    192     * Returns the format string (this controls the overall structure of the
    193     * label).
    194     *
    195     * @return The format string (never <code>null</code>).
    196     */
    197    public String getFormatString() {
    198        return this.formatString;
    199    }
    200
    201    /**
    202     * Returns the number formatter for the x-values.
    203     *
    204     * @return The number formatter (possibly <code>null</code>).
    205     */
    206    public NumberFormat getXFormat() {
    207        return this.xFormat;
    208    }
    209
    210    /**
    211     * Returns the date formatter for the x-values.
    212     *
    213     * @return The date formatter (possibly <code>null</code>).
    214     */
    215    public DateFormat getXDateFormat() {
    216        return this.xDateFormat;
    217    }
    218
    219    /**
    220     * Returns the number formatter for the y-values.
    221     *
    222     * @return The number formatter (possibly <code>null</code>).
    223     */
    224    public NumberFormat getYFormat() {
    225        return this.yFormat;
    226    }
    227
    228    /**
    229     * Returns the date formatter for the y-values.
    230     *
    231     * @return The date formatter (possibly <code>null</code>).
    232     */
    233    public DateFormat getYDateFormat() {
    234        return this.yDateFormat;
    235    }
    236
    237    /**
    238     * Generates a label string for an item in the dataset.
    239     *
    240     * @param dataset  the dataset (<code>null</code> not permitted).
    241     * @param series  the series (zero-based index).
    242     * @param item  the item (zero-based index).
    243     *
    244     * @return The label (possibly <code>null</code>).
    245     */
    246    public String generateLabelString(XYDataset dataset, int series, int item) {
    247        String result = null;
    248        Object[] items = createItemArray(dataset, series, item);
    249        result = MessageFormat.format(this.formatString, items);
    250        return result;
    251    }
    252
    253    /**
    254     * Returns the string representing a null value.
    255     *
    256     * @return The string representing a null value.
    257     *
    258     * @since 1.0.10
    259     */
    260    public String getNullYString() {
    261        return this.nullYString;
    262    }
    263
    264    /**
    265     * Creates the array of items that can be passed to the
    266     * {@link MessageFormat} class for creating labels.
    267     *
    268     * @param dataset  the dataset (<code>null</code> not permitted).
    269     * @param series  the series (zero-based index).
    270     * @param item  the item (zero-based index).
    271     *
    272     * @return An array of three items from the dataset formatted as
    273     *         <code>String</code> objects (never <code>null</code>).
    274     */
    275    protected Object[] createItemArray(XYDataset dataset, int series,
    276                                       int item) {
    277        Object[] result = new Object[3];
    278        result[0] = dataset.getSeriesKey(series).toString();
    279
    280        double x = dataset.getXValue(series, item);
    281        if (this.xDateFormat != null) {
    282            result[1] = this.xDateFormat.format(new Date((long) x));
    283        }
    284        else {
    285            result[1] = this.xFormat.format(x);
    286        }
    287
    288        double y = dataset.getYValue(series, item);
    289        if (Double.isNaN(y) && dataset.getY(series, item) == null) {
    290            result[2] = this.nullYString;
    291        }
    292        else {
    293            if (this.yDateFormat != null) {
    294                result[2] = this.yDateFormat.format(new Date((long) y));
    295            }
    296            else {
    297                result[2] = this.yFormat.format(y);
    298            }
    299        }
    300        return result;
    301    }
    302
    303    /**
    304     * Tests this object for equality with an arbitrary object.
    305     *
    306     * @param obj  the other object (<code>null</code> permitted).
    307     *
    308     * @return A boolean.
    309     */
    310    public boolean equals(Object obj) {
    311        if (obj == this) {
    312            return true;
    313        }
    314        if (!(obj instanceof AbstractXYItemLabelGenerator)) {
    315            return false;
    316        }
    317        AbstractXYItemLabelGenerator that = (AbstractXYItemLabelGenerator) obj;
    318        if (!this.formatString.equals(that.formatString)) {
    319            return false;
    320        }
    321        if (!ObjectUtilities.equal(this.xFormat, that.xFormat)) {
    322            return false;
    323        }
    324        if (!ObjectUtilities.equal(this.xDateFormat, that.xDateFormat)) {
    325            return false;
    326        }
    327        if (!ObjectUtilities.equal(this.yFormat, that.yFormat)) {
    328            return false;
    329        }
    330        if (!ObjectUtilities.equal(this.yDateFormat, that.yDateFormat)) {
    331            return false;
    332        }
    333        if (!this.nullYString.equals(that.nullYString)) {
    334            return false;
    335        }
    336        return true;
    337    }
    338
    339    /**
    340     * Returns a hash code for this instance.
    341     *
    342     * @return A hash code.
    343     */
    344    public int hashCode() {
    345        int result = 127;
    346        result = HashUtilities.hashCode(result, this.formatString);
    347        result = HashUtilities.hashCode(result, this.xFormat);
    348        result = HashUtilities.hashCode(result, this.xDateFormat);
    349        result = HashUtilities.hashCode(result, this.yFormat);
    350        result = HashUtilities.hashCode(result, this.yDateFormat);
    351        return result;
    352    }
    353
    354    /**
    355     * Returns an independent copy of the generator.
    356     *
    357     * @return A clone.
    358     *
    359     * @throws CloneNotSupportedException if cloning is not supported.
    360     */
    361    public Object clone() throws CloneNotSupportedException {
    362        AbstractXYItemLabelGenerator clone
    363                = (AbstractXYItemLabelGenerator) super.clone();
    364        if (this.xFormat != null) {
    365            clone.xFormat = (NumberFormat) this.xFormat.clone();
    366        }
    367        if (this.yFormat != null) {
    368            clone.yFormat = (NumberFormat) this.yFormat.clone();
    369        }
    370        if (this.xDateFormat != null) {
    371            clone.xDateFormat = (DateFormat) this.xDateFormat.clone();
    372        }
    373        if (this.yDateFormat != null) {
    374            clone.yDateFormat = (DateFormat) this.yDateFormat.clone();
    375        }
    376        return clone;
    377    }
    378
    379}