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