    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
    124    package org.jfree.chart.renderer.xy;
    125
    126    import java.awt.AlphaComposite;
    127    import java.awt.Composite;
    128    import java.awt.Font;
    129    import java.awt.GradientPaint;
    130    import java.awt.Graphics2D;
    131    import java.awt.Paint;
    132    import java.awt.Shape;
    133    import java.awt.Stroke;
    134    import java.awt.geom.Ellipse2D;
    135    import java.awt.geom.GeneralPath;
    136    import java.awt.geom.Line2D;
    137    import java.awt.geom.Point2D;
    138    import java.awt.geom.Rectangle2D;
    139    import java.io.Serializable;
    140    import java.util.ArrayList;
    141    import java.util.Collection;
    142    import java.util.Iterator;
    143    import java.util.List;
    144
    145    import org.jfree.chart.LegendItem;
    146    import org.jfree.chart.LegendItemCollection;
    147    import org.jfree.chart.annotations.Annotation;
    148    import org.jfree.chart.annotations.XYAnnotation;
    149    import org.jfree.chart.axis.ValueAxis;
    150    import org.jfree.chart.entity.EntityCollection;
    151    import org.jfree.chart.entity.XYItemEntity;
    152    import org.jfree.chart.event.AnnotationChangeEvent;
    153    import org.jfree.chart.event.AnnotationChangeListener;
    154    import org.jfree.chart.event.RendererChangeEvent;
    155    import org.jfree.chart.labels.ItemLabelPosition;
    156    import org.jfree.chart.labels.StandardXYSeriesLabelGenerator;
    157    import org.jfree.chart.labels.XYItemLabelGenerator;
    158    import org.jfree.chart.labels.XYSeriesLabelGenerator;
    159    import org.jfree.chart.labels.XYToolTipGenerator;
    160    import org.jfree.chart.plot.CrosshairState;
    161    import org.jfree.chart.plot.DrawingSupplier;
    162    import org.jfree.chart.plot.IntervalMarker;
    163    import org.jfree.chart.plot.Marker;
    164    import org.jfree.chart.plot.Plot;
    165    import org.jfree.chart.plot.PlotOrientation;
    166    import org.jfree.chart.plot.PlotRenderingInfo;
    167    import org.jfree.chart.plot.ValueMarker;
    168    import org.jfree.chart.plot.XYPlot;
    169    import org.jfree.chart.renderer.AbstractRenderer;
    170    import org.jfree.chart.urls.XYURLGenerator;
    171    import org.jfree.data.Range;
    172    import org.jfree.data.general.DatasetUtilities;
    173    import org.jfree.data.xy.XYDataset;
    174    import org.jfree.text.TextUtilities;
    175    import org.jfree.ui.GradientPaintTransformer;
    176    import org.jfree.ui.Layer;
    177    import org.jfree.ui.LengthAdjustmentType;
    178    import org.jfree.ui.RectangleAnchor;
    179    import org.jfree.ui.RectangleInsets;
    180    import org.jfree.util.ObjectList;
    181    import org.jfree.util.ObjectUtilities;
    182    import org.jfree.util.PublicCloneable;
    183
    184    /**
    185     * A base class that can be used to create new {@link XYItemRenderer}
    186     * implementations.
    187     */
    188    public 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    }