    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 * AbstractXYItemRenderer.java
    029 * ---------------------------
    030 * (C) Copyright 2002-2011, by Object Refinery Limited and Contributors.
    031 *
    032 * Original Author:  David Gilbert (for Object Refinery Limited);
    033 * Contributor(s):   Richard Atkinson;
    034 *                   Focus Computer Services Limited;
    035 *                   Tim Bardzil;
    036 *                   Sergei Ivanov;
    037 *                   Peter Kolb (patch 2809117);
    038 *                   Martin Krauskopf;
    039 *
    040 * Changes:
    041 * --------
    042 * 15-Mar-2002 : Version 1 (DG);
    043 * 09-Apr-2002 : Added a getToolTipGenerator() method reflecting the change in
    044 *               the XYItemRenderer interface (DG);
    045 * 05-Aug-2002 : Added a urlGenerator member variable to support HTML image
    046 *               maps (RA);
    047 * 20-Aug-2002 : Added property change events for the tooltip and URL
    048 *               generators (DG);
    049 * 22-Aug-2002 : Moved property change support into AbstractRenderer class (DG);
    050 * 23-Sep-2002 : Fixed errors reported by Checkstyle tool (DG);
    051 * 18-Nov-2002 : Added methods for drawing grid lines (DG);
    052 * 17-Jan-2003 : Moved plot classes into a separate package (DG);
    053 * 25-Mar-2003 : Implemented Serializable (DG);
    054 * 01-May-2003 : Modified initialise() return type and drawItem() method
    055 *               signature (DG);
    056 * 15-May-2003 : Modified to take into account the plot orientation (DG);
    057 * 21-May-2003 : Added labels to markers (DG);
    058 * 05-Jun-2003 : Added domain and range grid bands (sponsored by Focus Computer
    059 *               Services Ltd) (DG);
    060 * 27-Jul-2003 : Added getRangeType() to support stacked XY area charts (RA);
    061 * 31-Jul-2003 : Deprecated all but the default constructor (DG);
    062 * 13-Aug-2003 : Implemented Cloneable (DG);
    063 * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
    064 * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
    065 * 05-Nov-2003 : Fixed marker rendering bug (833623) (DG);
    066 * 11-Feb-2004 : Updated labelling for markers (DG);
    067 * 25-Feb-2004 : Added updateCrosshairValues() method.  Moved deprecated code
    068 *               to bottom of source file (DG);
    069 * 16-Apr-2004 : Added support for IntervalMarker in drawRangeMarker() method
    070 *               - thanks to Tim Bardzil (DG);
    071 * 05-May-2004 : Fixed bug (948310) where interval markers extend beyond axis
    072 *               range (DG);
    073 * 03-Jun-2004 : Fixed more bugs in drawing interval markers (DG);
    074 * 26-Aug-2004 : Added the addEntity() method (DG);
    075 * 29-Sep-2004 : Added annotation support (with layers) (DG);
    076 * 30-Sep-2004 : Moved drawRotatedString() from RefineryUtilities -->
    077 *               TextUtilities (DG);
    078 * 06-Oct-2004 : Added findDomainBounds() method and renamed
    079 *               getRangeExtent() --> findRangeBounds() (DG);
    080 * 07-Jan-2005 : Removed deprecated code (DG);
    081 * 27-Jan-2005 : Modified getLegendItem() to omit hidden series (DG);
    082 * 24-Feb-2005 : Added getLegendItems() method (DG);
    083 * 08-Mar-2005 : Fixed positioning of marker labels (DG);
    084 * 20-Apr-2005 : Renamed XYLabelGenerator --> XYItemLabelGenerator and
    085 *               added generators for legend labels, tooltips and URLs (DG);
    086 * 01-Jun-2005 : Handle one dimension of the marker label adjustment
    087 *               automatically (DG);
    088 * ------------- JFREECHART 1.0.x ---------------------------------------------
    089 * 20-Jul-2006 : Set dataset and series indices in LegendItem (DG);
    090 * 24-Oct-2006 : Respect alpha setting in markers (see patch 1567843 by Sergei
    091 *               Ivanov) (DG);
    092 * 24-Oct-2006 : Added code to draw outlines for interval markers (DG);
    093 * 24-Nov-2006 : Fixed cloning for legend item generators (DG);
    094 * 06-Feb-2007 : Added new updateCrosshairValues() method that takes into
    095 *               account multiple axis plots (see bug 1086307) (DG);
    096 * 20-Feb-2007 : Fixed equals() method implementation (DG);
    097 * 01-Mar-2007 : Fixed interval marker drawing (patch 1670686 thanks to
    098 *               Sergei Ivanov) (DG);
    099 * 22-Mar-2007 : Modified the tool tip generator look up (DG);
    100 * 23-Mar-2007 : Added drawDomainLine() method (DG);
    101 * 20-Apr-2007 : Updated getLegendItem() for renderer change, and deprecated
    102 *               itemLabelGenerator and toolTipGenerator override fields (DG);
    103 * 18-May-2007 : Set dataset and seriesKey for LegendItem (DG);
    104 * 12-Nov-2007 : Fixed domain and range band drawing methods (DG);
    105 * 07-Apr-2008 : Minor API doc update (DG);
    106 * 14-May-2008 : Updated addEntity() method to take plot orientation into
    107 *               account when the incoming area is null (DG);
    108 * 02-Jun-2008 : Added isPointInRect() method (DG);
    109 * 17-Jun-2008 : Apply legend shape, font and paint attributes (DG);
    110 * 09-Mar-2009 : Added getAnnotations() method (DG);
    111 * 27-Mar-2009 : Added new findDomainBounds() and findRangeBounds() methods to
    112 *               take account of hidden series (DG);
    113 * 01-Apr-2009 : Moved defaultEntityRadius up to superclass (DG);
    114 * 28-Apr-2009 : Updated getLegendItem() method to observe new
    115 *               'treatLegendShapeAsLine' flag (DG);
    116 * 24-Jun-2009 : Added support for annotation events - see patch 2809117
    117 *               by PK (DG);
    118 * 01-Sep-2009 : Bug 2840132 - set renderer index when drawing
    119 *               annotations (DG);
    120 * 06-Oct-2011 : Add utility methods to work with 1.4 API in GeneralPath (MK)
    121 *
    122 */
    123
    124package org.jfree.chart.renderer.xy;
    125
    126import java.awt.AlphaComposite;
    127import java.awt.Composite;
    128import java.awt.Font;
    129import java.awt.GradientPaint;
    130import java.awt.Graphics2D;
    131import java.awt.Paint;
    132import java.awt.Shape;
    133import java.awt.Stroke;
    134import java.awt.geom.Ellipse2D;
    135import java.awt.geom.GeneralPath;
    136import java.awt.geom.Line2D;
    137import java.awt.geom.Point2D;
    138import java.awt.geom.Rectangle2D;
    139import java.io.Serializable;
    140import java.util.ArrayList;
    141import java.util.Collection;
    142import java.util.Iterator;
    143import java.util.List;
    144
    145import org.jfree.chart.LegendItem;
    146import org.jfree.chart.LegendItemCollection;
    147import org.jfree.chart.annotations.Annotation;
    148import org.jfree.chart.annotations.XYAnnotation;
    149import org.jfree.chart.axis.ValueAxis;
    150import org.jfree.chart.entity.EntityCollection;
    151import org.jfree.chart.entity.XYItemEntity;
    152import org.jfree.chart.event.AnnotationChangeEvent;
    153import org.jfree.chart.event.AnnotationChangeListener;
    154import org.jfree.chart.event.RendererChangeEvent;
    155import org.jfree.chart.labels.ItemLabelPosition;
    156import org.jfree.chart.labels.StandardXYSeriesLabelGenerator;
    157import org.jfree.chart.labels.XYItemLabelGenerator;
    158import org.jfree.chart.labels.XYSeriesLabelGenerator;
    159import org.jfree.chart.labels.XYToolTipGenerator;
    160import org.jfree.chart.plot.CrosshairState;
    161import org.jfree.chart.plot.DrawingSupplier;
    162import org.jfree.chart.plot.IntervalMarker;
    163import org.jfree.chart.plot.Marker;
    164import org.jfree.chart.plot.Plot;
    165import org.jfree.chart.plot.PlotOrientation;
    166import org.jfree.chart.plot.PlotRenderingInfo;
    167import org.jfree.chart.plot.ValueMarker;
    168import org.jfree.chart.plot.XYPlot;
    169import org.jfree.chart.renderer.AbstractRenderer;
    170import org.jfree.chart.urls.XYURLGenerator;
    171import org.jfree.data.Range;
    172import org.jfree.data.general.DatasetUtilities;
    173import org.jfree.data.xy.XYDataset;
    174import org.jfree.text.TextUtilities;
    175import org.jfree.ui.GradientPaintTransformer;
    176import org.jfree.ui.Layer;
    177import org.jfree.ui.LengthAdjustmentType;
    178import org.jfree.ui.RectangleAnchor;
    179import org.jfree.ui.RectangleInsets;
    180import org.jfree.util.ObjectList;
    181import org.jfree.util.ObjectUtilities;
    182import org.jfree.util.PublicCloneable;
    183
    184/**
    185 * A base class that can be used to create new {@link XYItemRenderer}
    186 * implementations.
    187 */
    188public abstract class AbstractXYItemRenderer extends AbstractRenderer
    189        implements XYItemRenderer, AnnotationChangeListener,
    190        Cloneable, Serializable {
    191
    192    /** For serialization. */
    193    private static final long serialVersionUID = 8019124836026607990L;
    194
    195    /** The plot. */
    196    private XYPlot plot;
    197
    198    /** A list of item label generators (one per series). */
    199    private ObjectList itemLabelGeneratorList;
    200
    201    /** The base item label generator. */
    202    private XYItemLabelGenerator baseItemLabelGenerator;
    203
    204    /** A list of tool tip generators (one per series). */
    205    private ObjectList toolTipGeneratorList;
    206
    207    /** The base tool tip generator. */
    208    private XYToolTipGenerator baseToolTipGenerator;
    209
    210    /** The URL text generator. */
    211    private XYURLGenerator urlGenerator;
    212
    213    /**
    214     * Annotations to be drawn in the background layer ('underneath' the data
    215     * items).
    216     */
    217    private List backgroundAnnotations;
    218
    219    /**
    220     * Annotations to be drawn in the foreground layer ('on top' of the data
    221     * items).
    222     */
    223    private List foregroundAnnotations;
    224
    225    /** The legend item label generator. */
    226    private XYSeriesLabelGenerator legendItemLabelGenerator;
    227
    228    /** The legend item tool tip generator. */
    229    private XYSeriesLabelGenerator legendItemToolTipGenerator;
    230
    231    /** The legend item URL generator. */
    232    private XYSeriesLabelGenerator legendItemURLGenerator;
    233
    234    /**
    235     * Creates a renderer where the tooltip generator and the URL generator are
    236     * both <code>null</code>.
    237     */
    238    protected AbstractXYItemRenderer() {
    239        super();
    240        this.itemLabelGenerator = null;
    241        this.itemLabelGeneratorList = new ObjectList();
    242        this.toolTipGenerator = null;
    243        this.toolTipGeneratorList = new ObjectList();
    244        this.urlGenerator = null;
    245        this.backgroundAnnotations = new java.util.ArrayList();
    246        this.foregroundAnnotations = new java.util.ArrayList();
    247        this.legendItemLabelGenerator = new StandardXYSeriesLabelGenerator(
    248                "{0}");
    249    }
    250
    251    /**
    252     * Returns the number of passes through the data that the renderer requires
    253     * in order to draw the chart.  Most charts will require a single pass, but
    254     * some require two passes.
    255     *
    256     * @return The pass count.
    257     */
    258    public int getPassCount() {
    259        return 1;
    260    }
    261
    262    /**
    263     * Returns the plot that the renderer is assigned to.
    264     *
    265     * @return The plot (possibly <code>null</code>).
    266     */
    267    public XYPlot getPlot() {
    268        return this.plot;
    269    }
    270
    271    /**
    272     * Sets the plot that the renderer is assigned to.
    273     *
    274     * @param plot  the plot (<code>null</code> permitted).
    275     */
    276    public void setPlot(XYPlot plot) {
    277        this.plot = plot;
    278    }
    279
    280    /**
    281     * Initialises the renderer and returns a state object that should be
    282     * passed to all subsequent calls to the drawItem() method.
    283     * <P>
    284     * This method will be called before the first item is rendered, giving the
    285     * renderer an opportunity to initialise any state information it wants to
    286     * maintain.  The renderer can do nothing if it chooses.
    287     *
    288     * @param g2  the graphics device.
    289     * @param dataArea  the area inside the axes.
    290     * @param plot  the plot.
    291     * @param data  the data.
    292     * @param info  an optional info collection object to return data back to
    293     *              the caller.
    294     *
    295     * @return The renderer state (never <code>null</code>).
    296     */
    297    public XYItemRendererState initialise(Graphics2D g2,
    298                                          Rectangle2D dataArea,
    299                                          XYPlot plot,
    300                                          XYDataset data,
    301                                          PlotRenderingInfo info) {
    302
    303        XYItemRendererState state = new XYItemRendererState(info);
    304        return state;
    305
    306    }
    307
    308    // ITEM LABEL GENERATOR
    309
    310    /**
    311     * Returns the label generator for a data item.  This implementation simply
    312     * passes control to the {@link #getSeriesItemLabelGenerator(int)} method.
    313     * If, for some reason, you want a different generator for individual
    314     * items, you can override this method.
    315     *
    316     * @param series  the series index (zero based).
    317     * @param item  the item index (zero based).
    318     *
    319     * @return The generator (possibly <code>null</code>).
    320     */
    321    public XYItemLabelGenerator getItemLabelGenerator(int series, int item) {
    322        // return the generator for ALL series, if there is one...
    323        if (this.itemLabelGenerator != null) {
    324            return this.itemLabelGenerator;
    325        }
    326
    327        // otherwise look up the generator table
    328        XYItemLabelGenerator generator
    329            = (XYItemLabelGenerator) this.itemLabelGeneratorList.get(series);
    330        if (generator == null) {
    331            generator = this.baseItemLabelGenerator;
    332        }
    333        return generator;
    334    }
    335
    336    /**
    337     * Returns the item label generator for a series.
    338     *
    339     * @param series  the series index (zero based).
    340     *
    341     * @return The generator (possibly <code>null</code>).
    342     */
    343    public XYItemLabelGenerator getSeriesItemLabelGenerator(int series) {
    344        return (XYItemLabelGenerator) this.itemLabelGeneratorList.get(series);
    345    }
    346
    347    /**
    348     * Sets the item label generator for a series and sends a
    349     * {@link RendererChangeEvent} to all registered listeners.
    350     *
    351     * @param series  the series index (zero based).
    352     * @param generator  the generator (<code>null</code> permitted).
    353     */
    354    public void setSeriesItemLabelGenerator(int series,
    355                                            XYItemLabelGenerator generator) {
    356        this.itemLabelGeneratorList.set(series, generator);
    357        fireChangeEvent();
    358    }
    359
    360    /**
    361     * Returns the base item label generator.
    362     *
    363     * @return The generator (possibly <code>null</code>).
    364     */
    365    public XYItemLabelGenerator getBaseItemLabelGenerator() {
    366        return this.baseItemLabelGenerator;
    367    }
    368
    369    /**
    370     * Sets the base item label generator and sends a
    371     * {@link RendererChangeEvent} to all registered listeners.
    372     *
    373     * @param generator  the generator (<code>null</code> permitted).
    374     */
    375    public void setBaseItemLabelGenerator(XYItemLabelGenerator generator) {
    376        this.baseItemLabelGenerator = generator;
    377        fireChangeEvent();
    378    }
    379
    380    // TOOL TIP GENERATOR
    381
    382    /**
    383     * Returns the tool tip generator for a data item.  If, for some reason,
    384     * you want a different generator for individual items, you can override
    385     * this method.
    386     *
    387     * @param series  the series index (zero based).
    388     * @param item  the item index (zero based).
    389     *
    390     * @return The generator (possibly <code>null</code>).
    391     */
    392    public XYToolTipGenerator getToolTipGenerator(int series, int item) {
    393        // return the generator for ALL series, if there is one...
    394        if (this.toolTipGenerator != null) {
    395            return this.toolTipGenerator;
    396        }
    397
    398        // otherwise look up the generator table
    399        XYToolTipGenerator generator
    400                = (XYToolTipGenerator) this.toolTipGeneratorList.get(series);
    401        if (generator == null) {
    402            generator = this.baseToolTipGenerator;
    403        }
    404        return generator;
    405    }
    406
    407    /**
    408     * Returns the tool tip generator for a series.
    409     *
    410     * @param series  the series index (zero based).
    411     *
    412     * @return The generator (possibly <code>null</code>).
    413     */
    414    public XYToolTipGenerator getSeriesToolTipGenerator(int series) {
    415        return (XYToolTipGenerator) this.toolTipGeneratorList.get(series);
    416    }
    417
    418    /**
    419     * Sets the tool tip generator for a series and sends a
    420     * {@link RendererChangeEvent} to all registered listeners.
    421     *
    422     * @param series  the series index (zero based).
    423     * @param generator  the generator (<code>null</code> permitted).
    424     */
    425    public void setSeriesToolTipGenerator(int series,
    426                                          XYToolTipGenerator generator) {
    427        this.toolTipGeneratorList.set(series, generator);
    428        fireChangeEvent();
    429    }
    430
    431    /**
    432     * Returns the base tool tip generator.
    433     *
    434     * @return The generator (possibly <code>null</code>).
    435     *
    436     * @see #setBaseToolTipGenerator(XYToolTipGenerator)
    437     */
    438    public XYToolTipGenerator getBaseToolTipGenerator() {
    439        return this.baseToolTipGenerator;
    440    }
    441
    442    /**
    443     * Sets the base tool tip generator and sends a {@link RendererChangeEvent}
    444     * to all registered listeners.
    445     *
    446     * @param generator  the generator (<code>null</code> permitted).
    447     *
    448     * @see #getBaseToolTipGenerator()
    449     */
    450    public void setBaseToolTipGenerator(XYToolTipGenerator generator) {
    451        this.baseToolTipGenerator = generator;
    452        fireChangeEvent();
    453    }
    454
    455    // URL GENERATOR
    456
    457    /**
    458     * Returns the URL generator for HTML image maps.
    459     *
    460     * @return The URL generator (possibly <code>null</code>).
    461     */
    462    public XYURLGenerator getURLGenerator() {
    463        return this.urlGenerator;
    464    }
    465
    466    /**
    467     * Sets the URL generator for HTML image maps and sends a
    468     * {@link RendererChangeEvent} to all registered listeners.
    469     *
    470     * @param urlGenerator  the URL generator (<code>null</code> permitted).
    471     */
    472    public void setURLGenerator(XYURLGenerator urlGenerator) {
    473        this.urlGenerator = urlGenerator;
    474        fireChangeEvent();
    475    }
    476
    477    /**
    478     * Adds an annotation and sends a {@link RendererChangeEvent} to all
    479     * registered listeners.  The annotation is added to the foreground
    480     * layer.
    481     *
    482     * @param annotation  the annotation (<code>null</code> not permitted).
    483     */
    484    public void addAnnotation(XYAnnotation annotation) {
    485        // defer argument checking
    486        addAnnotation(annotation, Layer.FOREGROUND);
    487    }
    488
    489    /**
    490     * Adds an annotation to the specified layer and sends a
    491     * {@link RendererChangeEvent} to all registered listeners.
    492     *
    493     * @param annotation  the annotation (<code>null</code> not permitted).
    494     * @param layer  the layer (<code>null</code> not permitted).
    495     */
    496    public void addAnnotation(XYAnnotation annotation, Layer layer) {
    497        if (annotation == null) {
    498            throw new IllegalArgumentException("Null 'annotation' argument.");
    499        }
    500        if (layer.equals(Layer.FOREGROUND)) {
    501            this.foregroundAnnotations.add(annotation);
    502            annotation.addChangeListener(this);
    503            fireChangeEvent();
    504        }
    505        else if (layer.equals(Layer.BACKGROUND)) {
    506            this.backgroundAnnotations.add(annotation);
    507            annotation.addChangeListener(this);
    508            fireChangeEvent();
    509        }
    510        else {
    511            // should never get here
    512            throw new RuntimeException("Unknown layer.");
    513        }
    514    }
    515    /**
    516     * Removes the specified annotation and sends a {@link RendererChangeEvent}
    517     * to all registered listeners.
    518     *
    519     * @param annotation  the annotation to remove (<code>null</code> not
    520     *                    permitted).
    521     *
    522     * @return A boolean to indicate whether or not the annotation was
    523     *         successfully removed.
    524     */
    525    public boolean removeAnnotation(XYAnnotation annotation) {
    526        boolean removed = this.foregroundAnnotations.remove(annotation);
    527        removed = removed & this.backgroundAnnotations.remove(annotation);
    528        annotation.removeChangeListener(this);
    529        fireChangeEvent();
    530        return removed;
    531    }
    532
    533    /**
    534     * Removes all annotations and sends a {@link RendererChangeEvent}
    535     * to all registered listeners.
    536     */
    537    public void removeAnnotations() {
    538        for(int i = 0; i < this.foregroundAnnotations.size(); i++){
    539            XYAnnotation annotation
    540                    = (XYAnnotation) this.foregroundAnnotations.get(i);
    541            annotation.removeChangeListener(this);
    542        }
    543         for(int i = 0; i < this.backgroundAnnotations.size(); i++){
    544            XYAnnotation annotation
    545                    = (XYAnnotation) this.backgroundAnnotations.get(i);
    546            annotation.removeChangeListener(this);
    547        }
    548        this.foregroundAnnotations.clear();
    549        this.backgroundAnnotations.clear();
    550        fireChangeEvent();
    551    }
    552
    553
    554    /**
    555     * Receives notification of a change to an {@link Annotation} added to
    556     * this renderer.
    557     *
    558     * @param event  information about the event (not used here).
    559     *
    560     * @since 1.0.14
    561     */
    562    public void annotationChanged(AnnotationChangeEvent event) {
    563        fireChangeEvent();
    564    }
    565
    566    /**
    567     * Returns a collection of the annotations that are assigned to the
    568     * renderer.
    569     *
    570     * @return A collection of annotations (possibly empty but never
    571     *     <code>null</code>).
    572     *
    573     * @since 1.0.13
    574     */
    575    public Collection getAnnotations() {
    576        List result = new java.util.ArrayList(this.foregroundAnnotations);
    577        result.addAll(this.backgroundAnnotations);
    578        return result;
    579    }
    580
    581    /**
    582     * Returns the legend item label generator.
    583     *
    584     * @return The label generator (never <code>null</code>).
    585     *
    586     * @see #setLegendItemLabelGenerator(XYSeriesLabelGenerator)
    587     */
    588    public XYSeriesLabelGenerator getLegendItemLabelGenerator() {
    589        return this.legendItemLabelGenerator;
    590    }
    591
    592    /**
    593     * Sets the legend item label generator and sends a
    594     * {@link RendererChangeEvent} to all registered listeners.
    595     *
    596     * @param generator  the generator (<code>null</code> not permitted).
    597     *
    598     * @see #getLegendItemLabelGenerator()
    599     */
    600    public void setLegendItemLabelGenerator(XYSeriesLabelGenerator generator) {
    601        if (generator == null) {
    602            throw new IllegalArgumentException("Null 'generator' argument.");
    603        }
    604        this.legendItemLabelGenerator = generator;
    605        fireChangeEvent();
    606    }
    607
    608    /**
    609     * Returns the legend item tool tip generator.
    610     *
    611     * @return The tool tip generator (possibly <code>null</code>).
    612     *
    613     * @see #setLegendItemToolTipGenerator(XYSeriesLabelGenerator)
    614     */
    615    public XYSeriesLabelGenerator getLegendItemToolTipGenerator() {
    616        return this.legendItemToolTipGenerator;
    617    }
    618
    619    /**
    620     * Sets the legend item tool tip generator and sends a
    621     * {@link RendererChangeEvent} to all registered listeners.
    622     *
    623     * @param generator  the generator (<code>null</code> permitted).
    624     *
    625     * @see #getLegendItemToolTipGenerator()
    626     */
    627    public void setLegendItemToolTipGenerator(
    628            XYSeriesLabelGenerator generator) {
    629        this.legendItemToolTipGenerator = generator;
    630        fireChangeEvent();
    631    }
    632
    633    /**
    634     * Returns the legend item URL generator.
    635     *
    636     * @return The URL generator (possibly <code>null</code>).
    637     *
    638     * @see #setLegendItemURLGenerator(XYSeriesLabelGenerator)
    639     */
    640    public XYSeriesLabelGenerator getLegendItemURLGenerator() {
    641        return this.legendItemURLGenerator;
    642    }
    643
    644    /**
    645     * Sets the legend item URL generator and sends a
    646     * {@link RendererChangeEvent} to all registered listeners.
    647     *
    648     * @param generator  the generator (<code>null</code> permitted).
    649     *
    650     * @see #getLegendItemURLGenerator()
    651     */
    652    public void setLegendItemURLGenerator(XYSeriesLabelGenerator generator) {
    653        this.legendItemURLGenerator = generator;
    654        fireChangeEvent();
    655    }
    656
    657    /**
    658     * Returns the lower and upper bounds (range) of the x-values in the
    659     * specified dataset.
    660     *
    661     * @param dataset  the dataset (<code>null</code> permitted).
    662     *
    663     * @return The range (<code>null</code> if the dataset is <code>null</code>
    664     *         or empty).
    665     *
    666     * @see #findRangeBounds(XYDataset)
    667     */
    668    public Range findDomainBounds(XYDataset dataset) {
    669        return findDomainBounds(dataset, false);
    670    }
    671
    672    /**
    673     * Returns the lower and upper bounds (range) of the x-values in the
    674     * specified dataset.
    675     *
    676     * @param dataset  the dataset (<code>null</code> permitted).
    677     * @param includeInterval  include the interval (if any) for the dataset?
    678     *
    679     * @return The range (<code>null</code> if the dataset is <code>null</code>
    680     *         or empty).
    681     *
    682     * @since 1.0.13
    683     */
    684    protected Range findDomainBounds(XYDataset dataset,
    685            boolean includeInterval) {
    686        if (dataset == null) {
    687            return null;
    688        }
    689        if (getDataBoundsIncludesVisibleSeriesOnly()) {
    690            List visibleSeriesKeys = new ArrayList();
    691            int seriesCount = dataset.getSeriesCount();
    692            for (int s = 0; s < seriesCount; s++) {
    693                if (isSeriesVisible(s)) {
    694                    visibleSeriesKeys.add(dataset.getSeriesKey(s));
    695                }
    696            }
    697            return DatasetUtilities.findDomainBounds(dataset,
    698                    visibleSeriesKeys, includeInterval);
    699        }
    700        return DatasetUtilities.findDomainBounds(dataset, includeInterval);
    701    }
    702
    703    /**
    704     * Returns the range of values the renderer requires to display all the
    705     * items from the specified dataset.
    706     *
    707     * @param dataset  the dataset (<code>null</code> permitted).
    708     *
    709     * @return The range (<code>null</code> if the dataset is <code>null</code>
    710     *         or empty).
    711     *
    712     * @see #findDomainBounds(XYDataset)
    713     */
    714    public Range findRangeBounds(XYDataset dataset) {
    715        return findRangeBounds(dataset, false);
    716    }
    717
    718    /**
    719     * Returns the range of values the renderer requires to display all the
    720     * items from the specified dataset.
    721     *
    722     * @param dataset  the dataset (<code>null</code> permitted).
    723     * @param includeInterval  include the interval (if any) for the dataset?
    724     *
    725     * @return The range (<code>null</code> if the dataset is <code>null</code>
    726     *         or empty).
    727     *
    728     * @since 1.0.13
    729     */
    730    protected Range findRangeBounds(XYDataset dataset,
    731            boolean includeInterval) {
    732        if (dataset == null) {
    733            return null;
    734        }
    735        if (getDataBoundsIncludesVisibleSeriesOnly()) {
    736            List visibleSeriesKeys = new ArrayList();
    737            int seriesCount = dataset.getSeriesCount();
    738            for (int s = 0; s < seriesCount; s++) {
    739                if (isSeriesVisible(s)) {
    740                    visibleSeriesKeys.add(dataset.getSeriesKey(s));
    741                }
    742            }
    743            // the bounds should be calculated using just the items within
    744            // the current range of the x-axis...if there is one
    745            Range xRange = null;
    746            XYPlot p = getPlot();
    747            if (p != null) {
    748                ValueAxis xAxis = null;
    749                int index = p.getIndexOf(this);
    750                if (index >= 0) {
    751                    xAxis = this.plot.getDomainAxisForDataset(index);
    752                }
    753                if (xAxis != null) {
    754                    xRange = xAxis.getRange();
    755                }
    756            }
    757            if (xRange == null) {
    758                xRange = new Range(Double.NEGATIVE_INFINITY,
    759                        Double.POSITIVE_INFINITY);
    760            }
    761            return DatasetUtilities.findRangeBounds(dataset,
    762                    visibleSeriesKeys, xRange, includeInterval);
    763        }
    764        return DatasetUtilities.findRangeBounds(dataset, includeInterval);
    765    }
    766
    767    /**
    768     * Returns a (possibly empty) collection of legend items for the series
    769     * that this renderer is responsible for drawing.
    770     *
    771     * @return The legend item collection (never <code>null</code>).
    772     */
    773    public LegendItemCollection getLegendItems() {
    774        if (this.plot == null) {
    775            return new LegendItemCollection();
    776        }
    777        LegendItemCollection result = new LegendItemCollection();
    778        int index = this.plot.getIndexOf(this);
    779        XYDataset dataset = this.plot.getDataset(index);
    780        if (dataset != null) {
    781            int seriesCount = dataset.getSeriesCount();
    782            for (int i = 0; i < seriesCount; i++) {
    783                if (isSeriesVisibleInLegend(i)) {
    784                    LegendItem item = getLegendItem(index, i);
    785                    if (item != null) {
    786                        result.add(item);
    787                    }
    788                }
    789            }
    790
    791        }
    792        return result;
    793    }
    794
    795    /**
    796     * Returns a default legend item for the specified series.  Subclasses
    797     * should override this method to generate customised items.
    798     *
    799     * @param datasetIndex  the dataset index (zero-based).
    800     * @param series  the series index (zero-based).
    801     *
    802     * @return A legend item for the series.
    803     */
    804    public LegendItem getLegendItem(int datasetIndex, int series) {
    805        XYPlot xyplot = getPlot();
    806        if (xyplot == null) {
    807            return null;
    808        }
    809        XYDataset dataset = xyplot.getDataset(datasetIndex);
    810        if (dataset == null) {
    811            return null;
    812        }
    813        String label = this.legendItemLabelGenerator.generateLabel(dataset,
    814                series);
    815        String description = label;
    816        String toolTipText = null;
    817        if (getLegendItemToolTipGenerator() != null) {
    818            toolTipText = getLegendItemToolTipGenerator().generateLabel(
    819                    dataset, series);
    820        }
    821        String urlText = null;
    822        if (getLegendItemURLGenerator() != null) {
    823            urlText = getLegendItemURLGenerator().generateLabel(dataset,
    824                    series);
    825        }
    826        Shape shape = lookupLegendShape(series);
    827        Paint paint = lookupSeriesPaint(series);
    828        LegendItem item = new LegendItem(label, paint);
    829        item.setToolTipText(toolTipText);
    830        item.setURLText(urlText);
    831        item.setLabelFont(lookupLegendTextFont(series));
    832        Paint labelPaint = lookupLegendTextPaint(series);
    833        if (labelPaint != null) {
    834            item.setLabelPaint(labelPaint);
    835        }
    836        item.setSeriesKey(dataset.getSeriesKey(series));
    837        item.setSeriesIndex(series);
    838        item.setDataset(dataset);
    839        item.setDatasetIndex(datasetIndex);
    840
    841        if (getTreatLegendShapeAsLine()) {
    842            item.setLineVisible(true);
    843            item.setLine(shape);
    844            item.setLinePaint(paint);
    845            item.setShapeVisible(false);
    846        }
    847        else {
    848            Paint outlinePaint = lookupSeriesOutlinePaint(series);
    849            Stroke outlineStroke = lookupSeriesOutlineStroke(series);
    850            item.setOutlinePaint(outlinePaint);
    851            item.setOutlineStroke(outlineStroke);
    852        }
    853        return item;
    854    }
    855
    856    /**
    857     * Fills a band between two values on the axis.  This can be used to color
    858     * bands between the grid lines.
    859     *
    860     * @param g2  the graphics device.
    861     * @param plot  the plot.
    862     * @param axis  the domain axis.
    863     * @param dataArea  the data area.
    864     * @param start  the start value.
    865     * @param end  the end value.
    866     */
    867    public void fillDomainGridBand(Graphics2D g2, XYPlot plot, ValueAxis axis,
    868            Rectangle2D dataArea, double start, double end) {
    869
    870        double x1 = axis.valueToJava2D(start, dataArea,
    871                plot.getDomainAxisEdge());
    872        double x2 = axis.valueToJava2D(end, dataArea,
    873                plot.getDomainAxisEdge());
    874        Rectangle2D band;
    875        if (plot.getOrientation() == PlotOrientation.VERTICAL) {
    876            band = new Rectangle2D.Double(Math.min(x1, x2), dataArea.getMinY(),
    877                    Math.abs(x2 - x1), dataArea.getWidth());
    878        }
    879        else {
    880            band = new Rectangle2D.Double(dataArea.getMinX(), Math.min(x1, x2),
    881                    dataArea.getWidth(), Math.abs(x2 - x1));
    882        }
    883        Paint paint = plot.getDomainTickBandPaint();
    884
    885        if (paint != null) {
    886            g2.setPaint(paint);
    887            g2.fill(band);
    888        }
    889
    890    }
    891
    892    /**
    893     * Fills a band between two values on the range axis.  This can be used to
    894     * color bands between the grid lines.
    895     *
    896     * @param g2  the graphics device.
    897     * @param plot  the plot.
    898     * @param axis  the range axis.
    899     * @param dataArea  the data area.
    900     * @param start  the start value.
    901     * @param end  the end value.
    902     */
    903    public void fillRangeGridBand(Graphics2D g2, XYPlot plot, ValueAxis axis,
    904            Rectangle2D dataArea, double start, double end) {
    905
    906        double y1 = axis.valueToJava2D(start, dataArea,
    907                plot.getRangeAxisEdge());
    908        double y2 = axis.valueToJava2D(end, dataArea, plot.getRangeAxisEdge());
    909        Rectangle2D band;
    910        if (plot.getOrientation() == PlotOrientation.VERTICAL) {
    911            band = new Rectangle2D.Double(dataArea.getMinX(), Math.min(y1, y2),
    912                dataArea.getWidth(), Math.abs(y2 - y1));
    913        }
    914        else {
    915            band = new Rectangle2D.Double(Math.min(y1, y2), dataArea.getMinY(),
    916                    Math.abs(y2 - y1), dataArea.getHeight());
    917        }
    918        Paint paint = plot.getRangeTickBandPaint();
    919
    920        if (paint != null) {
    921            g2.setPaint(paint);
    922            g2.fill(band);
    923        }
    924
    925    }
    926
    927    /**
    928     * Draws a grid line against the range axis.
    929     *
    930     * @param g2  the graphics device.
    931     * @param plot  the plot.
    932     * @param axis  the value axis.
    933     * @param dataArea  the area for plotting data (not yet adjusted for any
    934     *                  3D effect).
    935     * @param value  the value at which the grid line should be drawn.
    936     */
    937    public void drawDomainGridLine(Graphics2D g2,
    938                                   XYPlot plot,
    939                                   ValueAxis axis,
    940                                   Rectangle2D dataArea,
    941                                   double value) {
    942
    943        Range range = axis.getRange();
    944        if (!range.contains(value)) {
    945            return;
    946        }
    947
    948        PlotOrientation orientation = plot.getOrientation();
    949        double v = axis.valueToJava2D(value, dataArea,
    950                plot.getDomainAxisEdge());
    951        Line2D line = null;
    952        if (orientation == PlotOrientation.HORIZONTAL) {
    953            line = new Line2D.Double(dataArea.getMinX(), v,
    954                    dataArea.getMaxX(), v);
    955        }
    956        else if (orientation == PlotOrientation.VERTICAL) {
    957            line = new Line2D.Double(v, dataArea.getMinY(), v,
    958                    dataArea.getMaxY());
    959        }
    960
    961        Paint paint = plot.getDomainGridlinePaint();
    962        Stroke stroke = plot.getDomainGridlineStroke();
    963        g2.setPaint(paint != null ? paint : Plot.DEFAULT_OUTLINE_PAINT);
    964        g2.setStroke(stroke != null ? stroke : Plot.DEFAULT_OUTLINE_STROKE);
    965        g2.draw(line);
    966
    967    }
    968
    969    /**
    970     * Draws a line perpendicular to the domain axis.
    971     *
    972     * @param g2  the graphics device.
    973     * @param plot  the plot.
    974     * @param axis  the value axis.
    975     * @param dataArea  the area for plotting data (not yet adjusted for any 3D
    976     *                  effect).
    977     * @param value  the value at which the grid line should be drawn.
    978     * @param paint  the paint (<code>null</code> not permitted).
    979     * @param stroke  the stroke (<code>null</code> not permitted).
    980     *
    981     * @since 1.0.5
    982     */
    983    public void drawDomainLine(Graphics2D g2, XYPlot plot, ValueAxis axis,
    984            Rectangle2D dataArea, double value, Paint paint, Stroke stroke) {
    985
    986        Range range = axis.getRange();
    987        if (!range.contains(value)) {
    988            return;
    989        }
    990
    991        PlotOrientation orientation = plot.getOrientation();
    992        Line2D line = null;
    993        double v = axis.valueToJava2D(value, dataArea,
    994                plot.getDomainAxisEdge());
    995        if (orientation == PlotOrientation.HORIZONTAL) {
    996            line = new Line2D.Double(dataArea.getMinX(), v, dataArea.getMaxX(),
    997                    v);
    998        }
    999        else if (orientation == PlotOrientation.VERTICAL) {
    1000            line = new Line2D.Double(v, dataArea.getMinY(), v,
    1001                    dataArea.getMaxY());
    1002        }
    1003
    1004        g2.setPaint(paint);
    1005        g2.setStroke(stroke);
    1006        g2.draw(line);
    1007
    1008    }
    1009
    1010    /**
    1011     * Draws a line perpendicular to the range axis.
    1012     *
    1013     * @param g2  the graphics device.
    1014     * @param plot  the plot.
    1015     * @param axis  the value axis.
    1016     * @param dataArea  the area for plotting data (not yet adjusted for any 3D
    1017     *                  effect).
    1018     * @param value  the value at which the grid line should be drawn.
    1019     * @param paint  the paint.
    1020     * @param stroke  the stroke.
    1021     */
    1022    public void drawRangeLine(Graphics2D g2,
    1023                              XYPlot plot,
    1024                              ValueAxis axis,
    1025                              Rectangle2D dataArea,
    1026                              double value,
    1027                              Paint paint,
    1028                              Stroke stroke) {
    1029
    1030        Range range = axis.getRange();
    1031        if (!range.contains(value)) {
    1032            return;
    1033        }
    1034
    1035        PlotOrientation orientation = plot.getOrientation();
    1036        Line2D line = null;
    1037        double v = axis.valueToJava2D(value, dataArea, plot.getRangeAxisEdge());
    1038        if (orientation == PlotOrientation.HORIZONTAL) {
    1039            line = new Line2D.Double(v, dataArea.getMinY(), v,
    1040                    dataArea.getMaxY());
    1041        }
    1042        else if (orientation == PlotOrientation.VERTICAL) {
    1043            line = new Line2D.Double(dataArea.getMinX(), v,
    1044                    dataArea.getMaxX(), v);
    1045        }
    1046
    1047        g2.setPaint(paint);
    1048        g2.setStroke(stroke);
    1049        g2.draw(line);
    1050
    1051    }
    1052
    1053    /**
    1054     * Draws a vertical line on the chart to represent a 'range marker'.
    1055     *
    1056     * @param g2  the graphics device.
    1057     * @param plot  the plot.
    1058     * @param domainAxis  the domain axis.
    1059     * @param marker  the marker line.
    1060     * @param dataArea  the axis data area.
    1061     */
    1062    public void drawDomainMarker(Graphics2D g2,
    1063                                 XYPlot plot,
    1064                                 ValueAxis domainAxis,
    1065                                 Marker marker,
    1066                                 Rectangle2D dataArea) {
    1067
    1068        if (marker instanceof ValueMarker) {
    1069            ValueMarker vm = (ValueMarker) marker;
    1070            double value = vm.getValue();
    1071            Range range = domainAxis.getRange();
    1072            if (!range.contains(value)) {
    1073                return;
    1074            }
    1075
    1076            double v = domainAxis.valueToJava2D(value, dataArea,
    1077                    plot.getDomainAxisEdge());
    1078
    1079            PlotOrientation orientation = plot.getOrientation();
    1080            Line2D line = null;
    1081            if (orientation == PlotOrientation.HORIZONTAL) {
    1082                line = new Line2D.Double(dataArea.getMinX(), v,
    1083                        dataArea.getMaxX(), v);
    1084            }
    1085            else if (orientation == PlotOrientation.VERTICAL) {
    1086                line = new Line2D.Double(v, dataArea.getMinY(), v,
    1087                        dataArea.getMaxY());
    1088            }
    1089
    1090            final Composite originalComposite = g2.getComposite();
    1091            g2.setComposite(AlphaComposite.getInstance(
    1092                    AlphaComposite.SRC_OVER, marker.getAlpha()));
    1093            g2.setPaint(marker.getPaint());
    1094            g2.setStroke(marker.getStroke());
    1095            g2.draw(line);
    1096
    1097            String label = marker.getLabel();
    1098            RectangleAnchor anchor = marker.getLabelAnchor();
    1099            if (label != null) {
    1100                Font labelFont = marker.getLabelFont();
    1101                g2.setFont(labelFont);
    1102                g2.setPaint(marker.getLabelPaint());
    1103                Point2D coordinates = calculateDomainMarkerTextAnchorPoint(
    1104                        g2, orientation, dataArea, line.getBounds2D(),
    1105                        marker.getLabelOffset(),
    1106                        LengthAdjustmentType.EXPAND, anchor);
    1107                TextUtilities.drawAlignedString(label, g2,
    1108                        (float) coordinates.getX(), (float) coordinates.getY(),
    1109                        marker.getLabelTextAnchor());
    1110            }
    1111            g2.setComposite(originalComposite);
    1112        }
    1113        else if (marker instanceof IntervalMarker) {
    1114            IntervalMarker im = (IntervalMarker) marker;
    1115            double start = im.getStartValue();
    1116            double end = im.getEndValue();
    1117            Range range = domainAxis.getRange();
    1118            if (!(range.intersects(start, end))) {
    1119                return;
    1120            }
    1121
    1122            double start2d = domainAxis.valueToJava2D(start, dataArea,
    1123                    plot.getDomainAxisEdge());
    1124            double end2d = domainAxis.valueToJava2D(end, dataArea,
    1125                    plot.getDomainAxisEdge());
    1126            double low = Math.min(start2d, end2d);
    1127            double high = Math.max(start2d, end2d);
    1128
    1129            PlotOrientation orientation = plot.getOrientation();
    1130            Rectangle2D rect = null;
    1131            if (orientation == PlotOrientation.HORIZONTAL) {
    1132                // clip top and bottom bounds to data area
    1133                low = Math.max(low, dataArea.getMinY());
    1134                high = Math.min(high, dataArea.getMaxY());
    1135                rect = new Rectangle2D.Double(dataArea.getMinX(),
    1136                        low, dataArea.getWidth(),
    1137                        high - low);
    1138            }
    1139            else if (orientation == PlotOrientation.VERTICAL) {
    1140                // clip left and right bounds to data area
    1141                low = Math.max(low, dataArea.getMinX());
    1142                high = Math.min(high, dataArea.getMaxX());
    1143                rect = new Rectangle2D.Double(low,
    1144                        dataArea.getMinY(), high - low,
    1145                        dataArea.getHeight());
    1146            }
    1147
    1148            final Composite originalComposite = g2.getComposite();
    1149            g2.setComposite(AlphaComposite.getInstance(
    1150                    AlphaComposite.SRC_OVER, marker.getAlpha()));
    1151            Paint p = marker.getPaint();
    1152            if (p instanceof GradientPaint) {
    1153                GradientPaint gp = (GradientPaint) p;
    1154                GradientPaintTransformer t = im.getGradientPaintTransformer();
    1155                if (t != null) {
    1156                    gp = t.transform(gp, rect);
    1157                }
    1158                g2.setPaint(gp);
    1159            }
    1160            else {
    1161                g2.setPaint(p);
    1162            }
    1163            g2.fill(rect);
    1164
    1165            // now draw the outlines, if visible...
    1166            if (im.getOutlinePaint() != null && im.getOutlineStroke() != null) {
    1167                if (orientation == PlotOrientation.VERTICAL) {
    1168                    Line2D line = new Line2D.Double();
    1169                    double y0 = dataArea.getMinY();
    1170                    double y1 = dataArea.getMaxY();
    1171                    g2.setPaint(im.getOutlinePaint());
    1172                    g2.setStroke(im.getOutlineStroke());
    1173                    if (range.contains(start)) {
    1174                        line.setLine(start2d, y0, start2d, y1);
    1175                        g2.draw(line);
    1176                    }
    1177                    if (range.contains(end)) {
    1178                        line.setLine(end2d, y0, end2d, y1);
    1179                        g2.draw(line);
    1180                    }
    1181                }
    1182                else { // PlotOrientation.HORIZONTAL
    1183                    Line2D line = new Line2D.Double();
    1184                    double x0 = dataArea.getMinX();
    1185                    double x1 = dataArea.getMaxX();
    1186                    g2.setPaint(im.getOutlinePaint());
    1187                    g2.setStroke(im.getOutlineStroke());
    1188                    if (range.contains(start)) {
    1189                        line.setLine(x0, start2d, x1, start2d);
    1190                        g2.draw(line);
    1191                    }
    1192                    if (range.contains(end)) {
    1193                        line.setLine(x0, end2d, x1, end2d);
    1194                        g2.draw(line);
    1195                    }
    1196                }
    1197            }
    1198
    1199            String label = marker.getLabel();
    1200            RectangleAnchor anchor = marker.getLabelAnchor();
    1201            if (label != null) {
    1202                Font labelFont = marker.getLabelFont();
    1203                g2.setFont(labelFont);
    1204                g2.setPaint(marker.getLabelPaint());
    1205                Point2D coordinates = calculateDomainMarkerTextAnchorPoint(
    1206                        g2, orientation, dataArea, rect,
    1207                        marker.getLabelOffset(), marker.getLabelOffsetType(),
    1208                        anchor);
    1209                TextUtilities.drawAlignedString(label, g2,
    1210                        (float) coordinates.getX(), (float) coordinates.getY(),
    1211                        marker.getLabelTextAnchor());
    1212            }
    1213            g2.setComposite(originalComposite);
    1214
    1215        }
    1216
    1217    }
    1218
    1219    /**
    1220     * Calculates the (x, y) coordinates for drawing a marker label.
    1221     *
    1222     * @param g2  the graphics device.
    1223     * @param orientation  the plot orientation.
    1224     * @param dataArea  the data area.
    1225     * @param markerArea  the rectangle surrounding the marker area.
    1226     * @param markerOffset  the marker label offset.
    1227     * @param labelOffsetType  the label offset type.
    1228     * @param anchor  the label anchor.
    1229     *
    1230     * @return The coordinates for drawing the marker label.
    1231     */
    1232    protected Point2D calculateDomainMarkerTextAnchorPoint(Graphics2D g2,
    1233            PlotOrientation orientation,
    1234            Rectangle2D dataArea,
    1235            Rectangle2D markerArea,
    1236            RectangleInsets markerOffset,
    1237            LengthAdjustmentType labelOffsetType,
    1238            RectangleAnchor anchor) {
    1239
    1240        Rectangle2D anchorRect = null;
    1241        if (orientation == PlotOrientation.HORIZONTAL) {
    1242            anchorRect = markerOffset.createAdjustedRectangle(markerArea,
    1243                    LengthAdjustmentType.CONTRACT, labelOffsetType);
    1244        }
    1245        else if (orientation == PlotOrientation.VERTICAL) {
    1246            anchorRect = markerOffset.createAdjustedRectangle(markerArea,
    1247                    labelOffsetType, LengthAdjustmentType.CONTRACT);
    1248        }
    1249        return RectangleAnchor.coordinates(anchorRect, anchor);
    1250
    1251    }
    1252
    1253    /**
    1254     * Draws a horizontal line across the chart to represent a 'range marker'.
    1255     *
    1256     * @param g2  the graphics device.
    1257     * @param plot  the plot.
    1258     * @param rangeAxis  the range axis.
    1259     * @param marker  the marker line.
    1260     * @param dataArea  the axis data area.
    1261     */
    1262    public void drawRangeMarker(Graphics2D g2,
    1263                                XYPlot plot,
    1264                                ValueAxis rangeAxis,
    1265                                Marker marker,
    1266                                Rectangle2D dataArea) {
    1267
    1268        if (marker instanceof ValueMarker) {
    1269            ValueMarker vm = (ValueMarker) marker;
    1270            double value = vm.getValue();
    1271            Range range = rangeAxis.getRange();
    1272            if (!range.contains(value)) {
    1273                return;
    1274            }
    1275
    1276            double v = rangeAxis.valueToJava2D(value, dataArea,
    1277                    plot.getRangeAxisEdge());
    1278            PlotOrientation orientation = plot.getOrientation();
    1279            Line2D line = null;
    1280            if (orientation == PlotOrientation.HORIZONTAL) {
    1281                line = new Line2D.Double(v, dataArea.getMinY(), v,
    1282                        dataArea.getMaxY());
    1283            }
    1284            else if (orientation == PlotOrientation.VERTICAL) {
    1285                line = new Line2D.Double(dataArea.getMinX(), v,
    1286                        dataArea.getMaxX(), v);
    1287            }
    1288            else {
    1289                throw new IllegalStateException("Unknown orientation.");
    1290            }
    1291
    1292            final Composite originalComposite = g2.getComposite();
    1293            g2.setComposite(AlphaComposite.getInstance(
    1294                    AlphaComposite.SRC_OVER, marker.getAlpha()));
    1295            g2.setPaint(marker.getPaint());
    1296            g2.setStroke(marker.getStroke());
    1297            g2.draw(line);
    1298
    1299            String label = marker.getLabel();
    1300            RectangleAnchor anchor = marker.getLabelAnchor();
    1301            if (label != null) {
    1302                Font labelFont = marker.getLabelFont();
    1303                g2.setFont(labelFont);
    1304                g2.setPaint(marker.getLabelPaint());
    1305                Point2D coordinates = calculateRangeMarkerTextAnchorPoint(
    1306                        g2, orientation, dataArea, line.getBounds2D(),
    1307                        marker.getLabelOffset(),
    1308                        LengthAdjustmentType.EXPAND, anchor);
    1309                TextUtilities.drawAlignedString(label, g2,
    1310                        (float) coordinates.getX(), (float) coordinates.getY(),
    1311                        marker.getLabelTextAnchor());
    1312            }
    1313            g2.setComposite(originalComposite);
    1314        }
    1315        else if (marker instanceof IntervalMarker) {
    1316            IntervalMarker im = (IntervalMarker) marker;
    1317            double start = im.getStartValue();
    1318            double end = im.getEndValue();
    1319            Range range = rangeAxis.getRange();
    1320            if (!(range.intersects(start, end))) {
    1321                return;
    1322            }
    1323
    1324            double start2d = rangeAxis.valueToJava2D(start, dataArea,
    1325                    plot.getRangeAxisEdge());
    1326            double end2d = rangeAxis.valueToJava2D(end, dataArea,
    1327                    plot.getRangeAxisEdge());
    1328            double low = Math.min(start2d, end2d);
    1329            double high = Math.max(start2d, end2d);
    1330
    1331            PlotOrientation orientation = plot.getOrientation();
    1332            Rectangle2D rect = null;
    1333            if (orientation == PlotOrientation.HORIZONTAL) {
    1334                // clip left and right bounds to data area
    1335                low = Math.max(low, dataArea.getMinX());
    1336                high = Math.min(high, dataArea.getMaxX());
    1337                rect = new Rectangle2D.Double(low,
    1338                        dataArea.getMinY(), high - low,
    1339                        dataArea.getHeight());
    1340            }
    1341            else if (orientation == PlotOrientation.VERTICAL) {
    1342                // clip top and bottom bounds to data area
    1343                low = Math.max(low, dataArea.getMinY());
    1344                high = Math.min(high, dataArea.getMaxY());
    1345                rect = new Rectangle2D.Double(dataArea.getMinX(),
    1346                        low, dataArea.getWidth(),
    1347                        high - low);
    1348            }
    1349
    1350            final Composite originalComposite = g2.getComposite();
    1351            g2.setComposite(AlphaComposite.getInstance(
    1352                    AlphaComposite.SRC_OVER, marker.getAlpha()));
    1353            Paint p = marker.getPaint();
    1354            if (p instanceof GradientPaint) {
    1355                GradientPaint gp = (GradientPaint) p;
    1356                GradientPaintTransformer t = im.getGradientPaintTransformer();
    1357                if (t != null) {
    1358                    gp = t.transform(gp, rect);
    1359                }
    1360                g2.setPaint(gp);
    1361            }
    1362            else {
    1363                g2.setPaint(p);
    1364            }
    1365            g2.fill(rect);
    1366
    1367            // now draw the outlines, if visible...
    1368            if (im.getOutlinePaint() != null && im.getOutlineStroke() != null) {
    1369                if (orientation == PlotOrientation.VERTICAL) {
    1370                    Line2D line = new Line2D.Double();
    1371                    double x0 = dataArea.getMinX();
    1372                    double x1 = dataArea.getMaxX();
    1373                    g2.setPaint(im.getOutlinePaint());
    1374                    g2.setStroke(im.getOutlineStroke());
    1375                    if (range.contains(start)) {
    1376                        line.setLine(x0, start2d, x1, start2d);
    1377                        g2.draw(line);
    1378                    }
    1379                    if (range.contains(end)) {
    1380                        line.setLine(x0, end2d, x1, end2d);
    1381                        g2.draw(line);
    1382                    }
    1383                }
    1384                else { // PlotOrientation.HORIZONTAL
    1385                    Line2D line = new Line2D.Double();
    1386                    double y0 = dataArea.getMinY();
    1387                    double y1 = dataArea.getMaxY();
    1388                    g2.setPaint(im.getOutlinePaint());
    1389                    g2.setStroke(im.getOutlineStroke());
    1390                    if (range.contains(start)) {
    1391                        line.setLine(start2d, y0, start2d, y1);
    1392                        g2.draw(line);
    1393                    }
    1394                    if (range.contains(end)) {
    1395                        line.setLine(end2d, y0, end2d, y1);
    1396                        g2.draw(line);
    1397                    }
    1398                }
    1399            }
    1400
    1401            String label = marker.getLabel();
    1402            RectangleAnchor anchor = marker.getLabelAnchor();
    1403            if (label != null) {
    1404                Font labelFont = marker.getLabelFont();
    1405                g2.setFont(labelFont);
    1406                g2.setPaint(marker.getLabelPaint());
    1407                Point2D coordinates = calculateRangeMarkerTextAnchorPoint(
    1408                        g2, orientation, dataArea, rect,
    1409                        marker.getLabelOffset(), marker.getLabelOffsetType(),
    1410                        anchor);
    1411                TextUtilities.drawAlignedString(label, g2,
    1412                        (float) coordinates.getX(), (float) coordinates.getY(),
    1413                        marker.getLabelTextAnchor());
    1414            }
    1415            g2.setComposite(originalComposite);
    1416        }
    1417    }
    1418
    1419    /**
    1420     * Calculates the (x, y) coordinates for drawing a marker label.
    1421     *
    1422     * @param g2  the graphics device.
    1423     * @param orientation  the plot orientation.
    1424     * @param dataArea  the data area.
    1425     * @param markerArea  the marker area.
    1426     * @param markerOffset  the marker offset.
    1427     * @param labelOffsetForRange  ??
    1428     * @param anchor  the label anchor.
    1429     *
    1430     * @return The coordinates for drawing the marker label.
    1431     */
    1432    private Point2D calculateRangeMarkerTextAnchorPoint(Graphics2D g2,
    1433                                      PlotOrientation orientation,
    1434                                      Rectangle2D dataArea,
    1435                                      Rectangle2D markerArea,
    1436                                      RectangleInsets markerOffset,
    1437                                      LengthAdjustmentType labelOffsetForRange,
    1438                                      RectangleAnchor anchor) {
    1439
    1440        Rectangle2D anchorRect = null;
    1441        if (orientation == PlotOrientation.HORIZONTAL) {
    1442            anchorRect = markerOffset.createAdjustedRectangle(markerArea,
    1443                    labelOffsetForRange, LengthAdjustmentType.CONTRACT);
    1444        }
    1445        else if (orientation == PlotOrientation.VERTICAL) {
    1446            anchorRect = markerOffset.createAdjustedRectangle(markerArea,
    1447                    LengthAdjustmentType.CONTRACT, labelOffsetForRange);
    1448        }
    1449        return RectangleAnchor.coordinates(anchorRect, anchor);
    1450
    1451    }
    1452
    1453    /**
    1454     * Returns a clone of the renderer.
    1455     *
    1456     * @return A clone.
    1457     *
    1458     * @throws CloneNotSupportedException if the renderer does not support
    1459     *         cloning.
    1460     */
    1461    protected Object clone() throws CloneNotSupportedException {
    1462        AbstractXYItemRenderer clone = (AbstractXYItemRenderer) super.clone();
    1463        // 'plot' : just retain reference, not a deep copy
    1464
    1465        if (this.itemLabelGenerator != null
    1466                && this.itemLabelGenerator instanceof PublicCloneable) {
    1467            PublicCloneable pc = (PublicCloneable) this.itemLabelGenerator;
    1468            clone.itemLabelGenerator = (XYItemLabelGenerator) pc.clone();
    1469        }
    1470        clone.itemLabelGeneratorList
    1471                = (ObjectList) this.itemLabelGeneratorList.clone();
    1472        if (this.baseItemLabelGenerator != null
    1473                && this.baseItemLabelGenerator instanceof PublicCloneable) {
    1474            PublicCloneable pc = (PublicCloneable) this.baseItemLabelGenerator;
    1475            clone.baseItemLabelGenerator = (XYItemLabelGenerator) pc.clone();
    1476        }
    1477
    1478        if (this.toolTipGenerator != null
    1479                && this.toolTipGenerator instanceof PublicCloneable) {
    1480            PublicCloneable pc = (PublicCloneable) this.toolTipGenerator;
    1481            clone.toolTipGenerator = (XYToolTipGenerator) pc.clone();
    1482        }
    1483        clone.toolTipGeneratorList
    1484                = (ObjectList) this.toolTipGeneratorList.clone();
    1485        if (this.baseToolTipGenerator != null
    1486                && this.baseToolTipGenerator instanceof PublicCloneable) {
    1487            PublicCloneable pc = (PublicCloneable) this.baseToolTipGenerator;
    1488            clone.baseToolTipGenerator = (XYToolTipGenerator) pc.clone();
    1489        }
    1490
    1491        if (this.legendItemLabelGenerator instanceof PublicCloneable) {
    1492            clone.legendItemLabelGenerator = (XYSeriesLabelGenerator)
    1493                    ObjectUtilities.clone(this.legendItemLabelGenerator);
    1494        }
    1495        if (this.legendItemToolTipGenerator instanceof PublicCloneable) {
    1496            clone.legendItemToolTipGenerator = (XYSeriesLabelGenerator)
    1497                    ObjectUtilities.clone(this.legendItemToolTipGenerator);
    1498        }
    1499        if (this.legendItemURLGenerator instanceof PublicCloneable) {
    1500            clone.legendItemURLGenerator = (XYSeriesLabelGenerator)
    1501                    ObjectUtilities.clone(this.legendItemURLGenerator);
    1502        }
    1503
    1504        clone.foregroundAnnotations = (List) ObjectUtilities.deepClone(
    1505                this.foregroundAnnotations);
    1506        clone.backgroundAnnotations = (List) ObjectUtilities.deepClone(
    1507                this.backgroundAnnotations);
    1508
    1509        return clone;
    1510    }
    1511
    1512    /**
    1513     * Tests this renderer for equality with another object.
    1514     *
    1515     * @param obj  the object (<code>null</code> permitted).
    1516     *
    1517     * @return <code>true</code> or <code>false</code>.
    1518     */
    1519    public boolean equals(Object obj) {
    1520        if (obj == this) {
    1521            return true;
    1522        }
    1523        if (!(obj instanceof AbstractXYItemRenderer)) {
    1524            return false;
    1525        }
    1526        AbstractXYItemRenderer that = (AbstractXYItemRenderer) obj;
    1527        if (!ObjectUtilities.equal(this.itemLabelGenerator,
    1528                that.itemLabelGenerator)) {
    1529            return false;
    1530        }
    1531        if (!this.itemLabelGeneratorList.equals(that.itemLabelGeneratorList)) {
    1532            return false;
    1533        }
    1534        if (!ObjectUtilities.equal(this.baseItemLabelGenerator,
    1535                that.baseItemLabelGenerator)) {
    1536            return false;
    1537        }
    1538        if (!ObjectUtilities.equal(this.toolTipGenerator,
    1539                that.toolTipGenerator)) {
    1540            return false;
    1541        }
    1542        if (!this.toolTipGeneratorList.equals(that.toolTipGeneratorList)) {
    1543            return false;
    1544        }
    1545        if (!ObjectUtilities.equal(this.baseToolTipGenerator,
    1546                that.baseToolTipGenerator)) {
    1547            return false;
    1548        }
    1549        if (!ObjectUtilities.equal(this.urlGenerator, that.urlGenerator)) {
    1550            return false;
    1551        }
    1552        if (!this.foregroundAnnotations.equals(that.foregroundAnnotations)) {
    1553            return false;
    1554        }
    1555        if (!this.backgroundAnnotations.equals(that.backgroundAnnotations)) {
    1556            return false;
    1557        }
    1558        if (!ObjectUtilities.equal(this.legendItemLabelGenerator,
    1559                that.legendItemLabelGenerator)) {
    1560            return false;
    1561        }
    1562        if (!ObjectUtilities.equal(this.legendItemToolTipGenerator,
    1563                that.legendItemToolTipGenerator)) {
    1564            return false;
    1565        }
    1566        if (!ObjectUtilities.equal(this.legendItemURLGenerator,
    1567                that.legendItemURLGenerator)) {
    1568            return false;
    1569        }
    1570        return super.equals(obj);
    1571    }
    1572
    1573    /**
    1574     * Returns the drawing supplier from the plot.
    1575     *
    1576     * @return The drawing supplier (possibly <code>null</code>).
    1577     */
    1578    public DrawingSupplier getDrawingSupplier() {
    1579        DrawingSupplier result = null;
    1580        XYPlot p = getPlot();
    1581        if (p != null) {
    1582            result = p.getDrawingSupplier();
    1583        }
    1584        return result;
    1585    }
    1586
    1587    /**
    1588     * Considers the current (x, y) coordinate and updates the crosshair point
    1589     * if it meets the criteria (usually means the (x, y) coordinate is the
    1590     * closest to the anchor point so far).
    1591     *
    1592     * @param crosshairState  the crosshair state (<code>null</code> permitted,
    1593     *                        but the method does nothing in that case).
    1594     * @param x  the x-value (in data space).
    1595     * @param y  the y-value (in data space).
    1596     * @param domainAxisIndex  the index of the domain axis for the point.
    1597     * @param rangeAxisIndex  the index of the range axis for the point.
    1598     * @param transX  the x-value translated to Java2D space.
    1599     * @param transY  the y-value translated to Java2D space.
    1600     * @param orientation  the plot orientation (<code>null</code> not
    1601     *                     permitted).
    1602     *
    1603     * @since 1.0.4
    1604     */
    1605    protected void updateCrosshairValues(CrosshairState crosshairState,
    1606            double x, double y, int domainAxisIndex, int rangeAxisIndex,
    1607            double transX, double transY, PlotOrientation orientation) {
    1608
    1609        if (orientation == null) {
    1610            throw new IllegalArgumentException("Null 'orientation' argument.");
    1611        }
    1612
    1613        if (crosshairState != null) {
    1614            // do we need to update the crosshair values?
    1615            if (this.plot.isDomainCrosshairLockedOnData()) {
    1616                if (this.plot.isRangeCrosshairLockedOnData()) {
    1617                    // both axes
    1618                    crosshairState.updateCrosshairPoint(x, y, domainAxisIndex,
    1619                            rangeAxisIndex, transX, transY, orientation);
    1620                }
    1621                else {
    1622                    // just the domain axis...
    1623                    crosshairState.updateCrosshairX(x, domainAxisIndex);
    1624                }
    1625            }
    1626            else {
    1627                if (this.plot.isRangeCrosshairLockedOnData()) {
    1628                    // just the range axis...
    1629                    crosshairState.updateCrosshairY(y, rangeAxisIndex);
    1630                }
    1631            }
    1632        }
    1633
    1634    }
    1635
    1636    /**
    1637     * Draws an item label.
    1638     *
    1639     * @param g2  the graphics device.
    1640     * @param orientation  the orientation.
    1641     * @param dataset  the dataset.
    1642     * @param series  the series index (zero-based).
    1643     * @param item  the item index (zero-based).
    1644     * @param x  the x coordinate (in Java2D space).
    1645     * @param y  the y coordinate (in Java2D space).
    1646     * @param negative  indicates a negative value (which affects the item
    1647     *                  label position).
    1648     */
    1649    protected void drawItemLabel(Graphics2D g2, PlotOrientation orientation,
    1650            XYDataset dataset, int series, int item, double x, double y,
    1651            boolean negative) {
    1652
    1653        XYItemLabelGenerator generator = getItemLabelGenerator(series, item);
    1654        if (generator != null) {
    1655            Font labelFont = getItemLabelFont(series, item);
    1656            Paint paint = getItemLabelPaint(series, item);
    1657            g2.setFont(labelFont);
    1658            g2.setPaint(paint);
    1659            String label = generator.generateLabel(dataset, series, item);
    1660
    1661            // get the label position..
    1662            ItemLabelPosition position = null;
    1663            if (!negative) {
    1664                position = getPositiveItemLabelPosition(series, item);
    1665            }
    1666            else {
    1667                position = getNegativeItemLabelPosition(series, item);
    1668            }
    1669
    1670            // work out the label anchor point...
    1671            Point2D anchorPoint = calculateLabelAnchorPoint(
    1672                    position.getItemLabelAnchor(), x, y, orientation);
    1673            TextUtilities.drawRotatedString(label, g2,
    1674                    (float) anchorPoint.getX(), (float) anchorPoint.getY(),
    1675                    position.getTextAnchor(), position.getAngle(),
    1676                    position.getRotationAnchor());
    1677        }
    1678
    1679    }
    1680
    1681    /**
    1682     * Draws all the annotations for the specified layer.
    1683     *
    1684     * @param g2  the graphics device.
    1685     * @param dataArea  the data area.
    1686     * @param domainAxis  the domain axis.
    1687     * @param rangeAxis  the range axis.
    1688     * @param layer  the layer.
    1689     * @param info  the plot rendering info.
    1690     */
    1691    public void drawAnnotations(Graphics2D g2,
    1692                                Rectangle2D dataArea,
    1693                                ValueAxis domainAxis,
    1694                                ValueAxis rangeAxis,
    1695                                Layer layer,
    1696                                PlotRenderingInfo info) {
    1697
    1698        Iterator iterator = null;
    1699        if (layer.equals(Layer.FOREGROUND)) {
    1700            iterator = this.foregroundAnnotations.iterator();
    1701        }
    1702        else if (layer.equals(Layer.BACKGROUND)) {
    1703            iterator = this.backgroundAnnotations.iterator();
    1704        }
    1705        else {
    1706            // should not get here
    1707            throw new RuntimeException("Unknown layer.");
    1708        }
    1709        while (iterator.hasNext()) {
    1710            XYAnnotation annotation = (XYAnnotation) iterator.next();
    1711            int index = this.plot.getIndexOf(this);
    1712            annotation.draw(g2, this.plot, dataArea, domainAxis, rangeAxis,
    1713                    index, info);
    1714        }
    1715
    1716    }
    1717
    1718    /**
    1719     * Adds an entity to the collection.
    1720     *
    1721     * @param entities  the entity collection being populated.
    1722     * @param area  the entity area (if <code>null</code> a default will be
    1723     *              used).
    1724     * @param dataset  the dataset.
    1725     * @param series  the series.
    1726     * @param item  the item.
    1727     * @param entityX  the entity's center x-coordinate in user space (only
    1728     *                 used if <code>area</code> is <code>null</code>).
    1729     * @param entityY  the entity's center y-coordinate in user space (only
    1730     *                 used if <code>area</code> is <code>null</code>).
    1731     */
    1732    protected void addEntity(EntityCollection entities, Shape area,
    1733                             XYDataset dataset, int series, int item,
    1734                             double entityX, double entityY) {
    1735        if (!getItemCreateEntity(series, item)) {
    1736            return;
    1737        }
    1738        Shape hotspot = area;
    1739        if (hotspot == null) {
    1740            double r = getDefaultEntityRadius();
    1741            double w = r * 2;
    1742            if (getPlot().getOrientation() == PlotOrientation.VERTICAL) {
    1743                hotspot = new Ellipse2D.Double(entityX - r, entityY - r, w, w);
    1744            }
    1745            else {
    1746                hotspot = new Ellipse2D.Double(entityY - r, entityX - r, w, w);
    1747            }
    1748        }
    1749        String tip = null;
    1750        XYToolTipGenerator generator = getToolTipGenerator(series, item);
    1751        if (generator != null) {
    1752            tip = generator.generateToolTip(dataset, series, item);
    1753        }
    1754        String url = null;
    1755        if (getURLGenerator() != null) {
    1756            url = getURLGenerator().generateURL(dataset, series, item);
    1757        }
    1758        XYItemEntity entity = new XYItemEntity(hotspot, dataset, series, item,
    1759                tip, url);
    1760        entities.add(entity);
    1761    }
    1762
    1763    /**
    1764     * Returns <code>true</code> if the specified point (x, y) falls within or
    1765     * on the boundary of the specified rectangle.
    1766     *
    1767     * @param rect  the rectangle (<code>null</code> not permitted).
    1768     * @param x  the x-coordinate.
    1769     * @param y  the y-coordinate.
    1770     *
    1771     * @return A boolean.
    1772     *
    1773     * @since 1.0.10
    1774     */
    1775    public static boolean isPointInRect(Rectangle2D rect, double x, double y) {
    1776        // TODO: For JFreeChart 1.2.0, this method should go in the
    1777        //       ShapeUtilities class
    1778        return (x >= rect.getMinX() && x <= rect.getMaxX()
    1779                && y >= rect.getMinY() && y <= rect.getMaxY());
    1780    }
    1781
    1782    /**
    1783     * Utility method delegating to {@link GeneralPath#moveTo} taking double as
    1784     * parameters.
    1785     *
    1786     * @param hotspot  the region under construction (<code>null</code> not
    1787     *           permitted);
    1788     * @param x  the x coordinate;
    1789     * @param y  the y coordinate;
    1790     *
    1791     * @since 1.0.14
    1792     */
    1793    protected static void moveTo(GeneralPath hotspot, double x, double y) {
    1794        hotspot.moveTo((float) x, (float) y);
    1795    }
    1796
    1797    /**
    1798     * Utility method delegating to {@link GeneralPath#lineTo} taking double as
    1799     * parameters.
    1800     *
    1801     * @param hotspot  the region under construction (<code>null</code> not
    1802     *           permitted);
    1803     * @param x  the x coordinate;
    1804     * @param y  the y coordinate;
    1805     *
    1806     * @since 1.0.14
    1807     */
    1808    protected static void lineTo(GeneralPath hotspot, double x, double y) {
    1809        hotspot.lineTo((float) x, (float) y);
    1810    }
    1811
    1812    // === DEPRECATED CODE ===
    1813
    1814    /**
    1815     * The item label generator for ALL series.
    1816     *
    1817     * @deprecated This field is redundant, use itemLabelGeneratorList and
    1818     *     baseItemLabelGenerator instead.  Deprecated as of version 1.0.6.
    1819     */
    1820    private XYItemLabelGenerator itemLabelGenerator;
    1821
    1822    /**
    1823     * The tool tip generator for ALL series.
    1824     *
    1825     * @deprecated This field is redundant, use tooltipGeneratorList and
    1826     *     baseToolTipGenerator instead.  Deprecated as of version 1.0.6.
    1827     */
    1828    private XYToolTipGenerator toolTipGenerator;
    1829
    1830    /**
    1831     * Returns the item label generator override.
    1832     *
    1833     * @return The generator (possibly <code>null</code>).
    1834     *
    1835     * @since 1.0.5
    1836     *
    1837     * @see #setItemLabelGenerator(XYItemLabelGenerator)
    1838     *
    1839     * @deprecated As of version 1.0.6, this override setting should not be
    1840     *     used.  You can use the base setting instead
    1841     *     ({@link #getBaseItemLabelGenerator()}).
    1842     */
    1843    public XYItemLabelGenerator getItemLabelGenerator() {
    1844        return this.itemLabelGenerator;
    1845    }
    1846
    1847    /**
    1848     * Sets the item label generator for ALL series and sends a
    1849     * {@link RendererChangeEvent} to all registered listeners.
    1850     *
    1851     * @param generator  the generator (<code>null</code> permitted).
    1852     *
    1853     * @see #getItemLabelGenerator()
    1854     *
    1855     * @deprecated As of version 1.0.6, this override setting should not be
    1856     *     used.  You can use the base setting instead
    1857     *     ({@link #setBaseItemLabelGenerator(XYItemLabelGenerator)}).
    1858     */
    1859    public void setItemLabelGenerator(XYItemLabelGenerator generator) {
    1860        this.itemLabelGenerator = generator;
    1861        fireChangeEvent();
    1862    }
    1863
    1864    /**
    1865     * Returns the override tool tip generator.
    1866     *
    1867     * @return The tool tip generator (possible <code>null</code>).
    1868     *
    1869     * @since 1.0.5
    1870     *
    1871     * @see #setToolTipGenerator(XYToolTipGenerator)
    1872     *
    1873     * @deprecated As of version 1.0.6, this override setting should not be
    1874     *     used.  You can use the base setting instead
    1875     *     ({@link #getBaseToolTipGenerator()}).
    1876     */
    1877    public XYToolTipGenerator getToolTipGenerator() {
    1878        return this.toolTipGenerator;
    1879    }
    1880
    1881    /**
    1882     * Sets the tool tip generator for ALL series and sends a
    1883     * {@link RendererChangeEvent} to all registered listeners.
    1884     *
    1885     * @param generator  the generator (<code>null</code> permitted).
    1886     *
    1887     * @see #getToolTipGenerator()
    1888     *
    1889     * @deprecated As of version 1.0.6, this override setting should not be
    1890     *     used.  You can use the base setting instead
    1891     *     ({@link #setBaseToolTipGenerator(XYToolTipGenerator)}).
    1892     */
    1893    public void setToolTipGenerator(XYToolTipGenerator generator) {
    1894        this.toolTipGenerator = generator;
    1895        fireChangeEvent();
    1896    }
    1897
    1898    /**
    1899     * Considers the current (x, y) coordinate and updates the crosshair point
    1900     * if it meets the criteria (usually means the (x, y) coordinate is the
    1901     * closest to the anchor point so far).
    1902     *
    1903     * @param crosshairState  the crosshair state (<code>null</code> permitted,
    1904     *                        but the method does nothing in that case).
    1905     * @param x  the x-value (in data space).
    1906     * @param y  the y-value (in data space).
    1907     * @param transX  the x-value translated to Java2D space.
    1908     * @param transY  the y-value translated to Java2D space.
    1909     * @param orientation  the plot orientation (<code>null</code> not
    1910     *                     permitted).
    1911     *
    1912     * @deprecated Use {@link #updateCrosshairValues(CrosshairState, double,
    1913     *         double, int, int, double, double, PlotOrientation)} -- see bug
    1914     *         report 1086307.
    1915     */
    1916    protected void updateCrosshairValues(CrosshairState crosshairState,
    1917            double x, double y, double transX, double transY,
    1918            PlotOrientation orientation) {
    1919        updateCrosshairValues(crosshairState, x, y, 0, 0, transX, transY,
    1920                orientation);
    1921    }
    1922
    1923
    1924}