    001    /* ===========================================================
    002     * JFreeChart : a free chart library for the Java(tm) platform
    003     * ===========================================================
    004     *
    005     * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
    006     *
    007     * Project Info:  http://www.jfree.org/jfreechart/index.html
    008     *
    009     * This library is free software; you can redistribute it and/or modify it
    010     * under the terms of the GNU Lesser General Public License as published by
    011     * the Free Software Foundation; either version 2.1 of the License, or
    012     * (at your option) any later version.
    013     *
    014     * This library is distributed in the hope that it will be useful, but
    015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017     * License for more details.
    018     *
    019     * You should have received a copy of the GNU Lesser General Public
    020     * License along with this library; if not, write to the Free Software
    021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022     * USA.
    023     *
    024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025     * in the United States and other countries.]
    026     *
    027     * ---------------------
    028     * AbstractRenderer.java
    029     * ---------------------
    030     * (C) Copyright 2002-2007, by Object Refinery Limited.
    031     *
    032     * Original Author:  David Gilbert (for Object Refinery Limited);
    033     * Contributor(s):   Nicolas Brodu;
    034     *
    035     * $Id: AbstractRenderer.java,v 1.22.2.9 2007/03/22 16:27:46 mungady Exp $
    036     *
    037     * Changes:
    038     * --------
    039     * 22-Aug-2002 : Version 1, draws code out of AbstractXYItemRenderer to share
    040     *               with AbstractCategoryItemRenderer (DG);
    041     * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
    042     * 06-Nov-2002 : Moved to the com.jrefinery.chart.renderer package (DG);
    043     * 21-Nov-2002 : Added a paint table for the renderer to use (DG);
    044     * 17-Jan-2003 : Moved plot classes into a separate package (DG);
    045     * 25-Mar-2003 : Implemented Serializable (DG);
    046     * 29-Apr-2003 : Added valueLabelFont and valueLabelPaint attributes, based on
    047     *               code from Arnaud Lelievre (DG);
    048     * 29-Jul-2003 : Amended code that doesn't compile with JDK 1.2.2 (DG);
    049     * 13-Aug-2003 : Implemented Cloneable (DG);
    050     * 15-Sep-2003 : Fixed serialization (NB);
    051     * 17-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
    052     * 07-Oct-2003 : Moved PlotRenderingInfo into RendererState to allow for
    053     *               multiple threads using a single renderer (DG);
    054     * 20-Oct-2003 : Added missing setOutlinePaint() method (DG);
    055     * 23-Oct-2003 : Split item label attributes into 'positive' and 'negative'
    056     *               values (DG);
    057     * 26-Nov-2003 : Added methods to get the positive and negative item label
    058     *               positions (DG);
    059     * 01-Mar-2004 : Modified readObject() method to prevent null pointer exceptions
    060     *               after deserialization (DG);
    061     * 19-Jul-2004 : Fixed bug in getItemLabelFont(int, int) method (DG);
    062     * 04-Oct-2004 : Updated equals() method, eliminated use of NumberUtils,
    063     *               renamed BooleanUtils --> BooleanUtilities, ShapeUtils -->
    064     *               ShapeUtilities (DG);
    065     * 15-Mar-2005 : Fixed serialization of baseFillPaint (DG);
    066     * 16-May-2005 : Base outline stroke should never be null (DG);
    067     * 01-Jun-2005 : Added hasListener() method for unit testing (DG);
    068     * 08-Jun-2005 : Fixed equals() method to handle GradientPaint (DG);
    069     * ------------- JFREECHART 1.0.x ---------------------------------------------
    070     * 02-Feb-2007 : Minor API doc update (DG);
    071     * 19-Feb-2007 : Fixes for clone() method (DG);
    072     * 28-Feb-2007 : Use cached event to signal changes (DG);
    073     *
    074     */
    075
    076    package org.jfree.chart.renderer;
    077
    078    import java.awt.BasicStroke;
    079    import java.awt.Color;
    080    import java.awt.Font;
    081    import java.awt.Paint;
    082    import java.awt.Shape;
    083    import java.awt.Stroke;
    084    import java.awt.geom.Point2D;
    085    import java.awt.geom.Rectangle2D;
    086    import java.io.IOException;
    087    import java.io.ObjectInputStream;
    088    import java.io.ObjectOutputStream;
    089    import java.io.Serializable;
    090    import java.util.Arrays;
    091    import java.util.EventListener;
    092    import java.util.List;
    093
    094    import javax.swing.event.EventListenerList;
    095
    096    import org.jfree.chart.event.RendererChangeEvent;
    097    import org.jfree.chart.event.RendererChangeListener;
    098    import org.jfree.chart.labels.ItemLabelAnchor;
    099    import org.jfree.chart.labels.ItemLabelPosition;
    100    import org.jfree.chart.plot.DrawingSupplier;
    101    import org.jfree.chart.plot.PlotOrientation;
    102    import org.jfree.io.SerialUtilities;
    103    import org.jfree.ui.TextAnchor;
    104    import org.jfree.util.BooleanList;
    105    import org.jfree.util.BooleanUtilities;
    106    import org.jfree.util.ObjectList;
    107    import org.jfree.util.ObjectUtilities;
    108    import org.jfree.util.PaintList;
    109    import org.jfree.util.PaintUtilities;
    110    import org.jfree.util.ShapeList;
    111    import org.jfree.util.ShapeUtilities;
    112    import org.jfree.util.StrokeList;
    113
    114    /**
    115     * Base class providing common services for renderers.  Most methods that update
    116     * attributes of the renderer will fire a {@link RendererChangeEvent}, which
    117     * normally means the plot that owns the renderer will receive notification that
    118     * the renderer has been changed (the plot will, in turn, notify the chart).
    119     */
    120    public abstract class AbstractRenderer implements Cloneable, Serializable {
    121
    122        /** For serialization. */
    123        private static final long serialVersionUID = -828267569428206075L;
    124
    125        /** Zero represented as a <code>Double</code>. */
    126        public static final Double ZERO = new Double(0.0);
    127
    128        /** The default paint. */
    129        public static final Paint DEFAULT_PAINT = Color.blue;
    130
    131        /** The default outline paint. */
    132        public static final Paint DEFAULT_OUTLINE_PAINT = Color.gray;
    133
    134        /** The default stroke. */
    135        public static final Stroke DEFAULT_STROKE = new BasicStroke(1.0f);
    136
    137        /** The default outline stroke. */
    138        public static final Stroke DEFAULT_OUTLINE_STROKE = new BasicStroke(1.0f);
    139
    140        /** The default shape. */
    141        public static final Shape DEFAULT_SHAPE
    142                = new Rectangle2D.Double(-3.0, -3.0, 6.0, 6.0);
    143
    144        /** The default value label font. */
    145        public static final Font DEFAULT_VALUE_LABEL_FONT
    146                = new Font("SansSerif", Font.PLAIN, 10);
    147
    148        /** The default value label paint. */
    149        public static final Paint DEFAULT_VALUE_LABEL_PAINT = Color.black;
    150
    151        /** A flag that controls the visibility of ALL series. */
    152        private Boolean seriesVisible;
    153
    154        /** A list of flags that controls whether or not each series is visible. */
    155        private BooleanList seriesVisibleList;
    156
    157        /** The default visibility for each series. */
    158        private boolean baseSeriesVisible;
    159
    160        /** A flag that controls the visibility of ALL series in the legend. */
    161        private Boolean seriesVisibleInLegend;
    162
    163        /**
    164         * A list of flags that controls whether or not each series is visible in
    165         * the legend.
    166         */
    167        private BooleanList seriesVisibleInLegendList;
    168
    169        /** The default visibility for each series in the legend. */
    170        private boolean baseSeriesVisibleInLegend;
    171
    172        /** The paint for ALL series (optional). */
    173        private transient Paint paint;
    174
    175        /** The paint list. */
    176        private PaintList paintList;
    177
    178        /** The base paint. */
    179        private transient Paint basePaint;
    180
    181        /** The fill paint for ALL series (optional). */
    182        private transient Paint fillPaint;
    183
    184        /** The fill paint list. */
    185        private PaintList fillPaintList;
    186
    187        /** The base fill paint. */
    188        private transient Paint baseFillPaint;
    189
    190        /** The outline paint for ALL series (optional). */
    191        private transient Paint outlinePaint;
    192
    193        /** The outline paint list. */
    194        private PaintList outlinePaintList;
    195
    196        /** The base outline paint. */
    197        private transient Paint baseOutlinePaint;
    198
    199        /** The stroke for ALL series (optional). */
    200        private transient Stroke stroke;
    201
    202        /** The stroke list. */
    203        private StrokeList strokeList;
    204
    205        /** The base stroke. */
    206        private transient Stroke baseStroke;
    207
    208        /** The outline stroke for ALL series (optional). */
    209        private transient Stroke outlineStroke;
    210
    211        /** The outline stroke list. */
    212        private StrokeList outlineStrokeList;
    213
    214        /** The base outline stroke. */
    215        private transient Stroke baseOutlineStroke;
    216
    217        /** The shape for ALL series (optional). */
    218        private transient Shape shape;
    219
    220        /** A shape list. */
    221        private ShapeList shapeList;
    222
    223        /** The base shape. */
    224        private transient Shape baseShape;
    225
    226        /** Visibility of the item labels for ALL series (optional). */
    227        private Boolean itemLabelsVisible;
    228
    229        /** Visibility of the item labels PER series. */
    230        private BooleanList itemLabelsVisibleList;
    231
    232        /** The base item labels visible. */
    233        private Boolean baseItemLabelsVisible;
    234
    235        /** The item label font for ALL series (optional). */
    236        private Font itemLabelFont;
    237
    238        /** The item label font list (one font per series). */
    239        private ObjectList itemLabelFontList;
    240
    241        /** The base item label font. */
    242        private Font baseItemLabelFont;
    243
    244        /** The item label paint for ALL series. */
    245        private transient Paint itemLabelPaint;
    246
    247        /** The item label paint list (one paint per series). */
    248        private PaintList itemLabelPaintList;
    249
    250        /** The base item label paint. */
    251        private transient Paint baseItemLabelPaint;
    252
    253        /** The positive item label position for ALL series (optional). */
    254        private ItemLabelPosition positiveItemLabelPosition;
    255
    256        /** The positive item label position (per series). */
    257        private ObjectList positiveItemLabelPositionList;
    258
    259        /** The fallback positive item label position. */
    260        private ItemLabelPosition basePositiveItemLabelPosition;
    261
    262        /** The negative item label position for ALL series (optional). */
    263        private ItemLabelPosition negativeItemLabelPosition;
    264
    265        /** The negative item label position (per series). */
    266        private ObjectList negativeItemLabelPositionList;
    267
    268        /** The fallback negative item label position. */
    269        private ItemLabelPosition baseNegativeItemLabelPosition;
    270
    271        /** The item label anchor offset. */
    272        private double itemLabelAnchorOffset = 2.0;
    273
    274        /**
    275         * A flag that controls whether or not entities are generated for
    276         * ALL series (optional).
    277         */
    278        private Boolean createEntities;
    279
    280        /**
    281         * Flags that control whether or not entities are generated for each
    282         * series.  This will be overridden by 'createEntities'.
    283         */
    284        private BooleanList createEntitiesList;
    285
    286        /**
    287         * The default flag that controls whether or not entities are generated.
    288         * This flag is used when both the above flags return null.
    289         */
    290        private boolean baseCreateEntities;
    291
    292        /** Storage for registered change listeners. */
    293        private transient EventListenerList listenerList;
    294
    295        /** An event for re-use. */
    296        private transient RendererChangeEvent event;
    297
    298        /**
    299         * Default constructor.
    300         */
    301        public AbstractRenderer() {
    302
    303            this.seriesVisible = null;
    304            this.seriesVisibleList = new BooleanList();
    305            this.baseSeriesVisible = true;
    306
    307            this.seriesVisibleInLegend = null;
    308            this.seriesVisibleInLegendList = new BooleanList();
    309            this.baseSeriesVisibleInLegend = true;
    310
    311            this.paint = null;
    312            this.paintList = new PaintList();
    313            this.basePaint = DEFAULT_PAINT;
    314
    315            this.fillPaint = null;
    316            this.fillPaintList = new PaintList();
    317            this.baseFillPaint = Color.white;
    318
    319            this.outlinePaint = null;
    320            this.outlinePaintList = new PaintList();
    321            this.baseOutlinePaint = DEFAULT_OUTLINE_PAINT;
    322
    323            this.stroke = null;
    324            this.strokeList = new StrokeList();
    325            this.baseStroke = DEFAULT_STROKE;
    326
    327            this.outlineStroke = null;
    328            this.outlineStrokeList = new StrokeList();
    329            this.baseOutlineStroke = DEFAULT_OUTLINE_STROKE;
    330
    331            this.shape = null;
    332            this.shapeList = new ShapeList();
    333            this.baseShape = DEFAULT_SHAPE;
    334
    335            this.itemLabelsVisible = null;
    336            this.itemLabelsVisibleList = new BooleanList();
    337            this.baseItemLabelsVisible = Boolean.FALSE;
    338
    339            this.itemLabelFont = null;
    340            this.itemLabelFontList = new ObjectList();
    341            this.baseItemLabelFont = new Font("SansSerif", Font.PLAIN, 10);
    342
    343            this.itemLabelPaint = null;
    344            this.itemLabelPaintList = new PaintList();
    345            this.baseItemLabelPaint = Color.black;
    346
    347            this.positiveItemLabelPosition = null;
    348            this.positiveItemLabelPositionList = new ObjectList();
    349            this.basePositiveItemLabelPosition = new ItemLabelPosition(
    350                    ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER);
    351
    352            this.negativeItemLabelPosition = null;
    353            this.negativeItemLabelPositionList = new ObjectList();
    354            this.baseNegativeItemLabelPosition = new ItemLabelPosition(
    355                    ItemLabelAnchor.OUTSIDE6, TextAnchor.TOP_CENTER);
    356
    357            this.createEntities = null;
    358            this.createEntitiesList = new BooleanList();
    359            this.baseCreateEntities = true;
    360
    361            this.listenerList = new EventListenerList();
    362
    363        }
    364
    365        /**
    366         * Returns the drawing supplier from the plot.
    367         *
    368         * @return The drawing supplier.
    369         */
    370        public abstract DrawingSupplier getDrawingSupplier();
    371
    372        // SERIES VISIBLE (not yet respected by all renderers)
    373
    374        /**
    375         * Returns a boolean that indicates whether or not the specified item
    376         * should be drawn (this is typically used to hide an entire series).
    377         *
    378         * @param series  the series index.
    379         * @param item  the item index.
    380         *
    381         * @return A boolean.
    382         */
    383        public boolean getItemVisible(int series, int item) {
    384            return isSeriesVisible(series);
    385        }
    386
    387        /**
    388         * Returns a boolean that indicates whether or not the specified series
    389         * should be drawn.
    390         *
    391         * @param series  the series index.
    392         *
    393         * @return A boolean.
    394         */
    395        public boolean isSeriesVisible(int series) {
    396            boolean result = this.baseSeriesVisible;
    397            if (this.seriesVisible != null) {
    398                result = this.seriesVisible.booleanValue();
    399            }
    400            else {
    401                Boolean b = this.seriesVisibleList.getBoolean(series);
    402                if (b != null) {
    403                    result = b.booleanValue();
    404                }
    405            }
    406            return result;
    407        }
    408
    409        /**
    410         * Returns the flag that controls the visibility of ALL series.  This flag
    411         * overrides the per series and default settings - you must set it to
    412         * <code>null</code> if you want the other settings to apply.
    413         *
    414         * @return The flag (possibly <code>null</code>).
    415         *
    416         * @see #setSeriesVisible(Boolean)
    417         */
    418        public Boolean getSeriesVisible() {
    419            return this.seriesVisible;
    420        }
    421
    422        /**
    423         * Sets the flag that controls the visibility of ALL series and sends a
    424         * {@link RendererChangeEvent} to all registered listeners.  This flag
    425         * overrides the per series and default settings - you must set it to
    426         * <code>null</code> if you want the other settings to apply.
    427         *
    428         * @param visible  the flag (<code>null</code> permitted).
    429         *
    430         * @see #getSeriesVisible()
    431         */
    432        public void setSeriesVisible(Boolean visible) {
    433             setSeriesVisible(visible, true);
    434        }
    435
    436        /**
    437         * Sets the flag that controls the visibility of ALL series and sends a
    438         * {@link RendererChangeEvent} to all registered listeners.  This flag
    439         * overrides the per series and default settings - you must set it to
    440         * <code>null</code> if you want the other settings to apply.
    441         *
    442         * @param visible  the flag (<code>null</code> permitted).
    443         * @param notify  notify listeners?
    444         *
    445         * @see #getSeriesVisible()
    446         */
    447        public void setSeriesVisible(Boolean visible, boolean notify) {
    448            this.seriesVisible = visible;
    449            if (notify) {
    450                fireChangeEvent();
    451            }
    452        }
    453
    454        /**
    455         * Returns the flag that controls whether a series is visible.
    456         *
    457         * @param series  the series index (zero-based).
    458         *
    459         * @return The flag (possibly <code>null</code>).
    460         *
    461         * @see #setSeriesVisible(int, Boolean)
    462         */
    463        public Boolean getSeriesVisible(int series) {
    464            return this.seriesVisibleList.getBoolean(series);
    465        }
    466
    467        /**
    468         * Sets the flag that controls whether a series is visible and sends a
    469         * {@link RendererChangeEvent} to all registered listeners.
    470         *
    471         * @param series  the series index (zero-based).
    472         * @param visible  the flag (<code>null</code> permitted).
    473         *
    474         * @see #getSeriesVisible(int)
    475         */
    476        public void setSeriesVisible(int series, Boolean visible) {
    477            setSeriesVisible(series, visible, true);
    478        }
    479
    480        /**
    481         * Sets the flag that controls whether a series is visible and, if
    482         * requested, sends a {@link RendererChangeEvent} to all registered
    483         * listeners.
    484         *
    485         * @param series  the series index.
    486         * @param visible  the flag (<code>null</code> permitted).
    487         * @param notify  notify listeners?
    488         *
    489         * @see #getSeriesVisible(int)
    490         */
    491        public void setSeriesVisible(int series, Boolean visible, boolean notify) {
    492            this.seriesVisibleList.setBoolean(series, visible);
    493            if (notify) {
    494                fireChangeEvent();
    495            }
    496        }
    497
    498        /**
    499         * Returns the base visibility for all series.
    500         *
    501         * @return The base visibility.
    502         *
    503         * @see #setBaseSeriesVisible(boolean)
    504         */
    505        public boolean getBaseSeriesVisible() {
    506            return this.baseSeriesVisible;
    507        }
    508
    509        /**
    510         * Sets the base visibility and sends a {@link RendererChangeEvent}
    511         * to all registered listeners.
    512         *
    513         * @param visible  the flag.
    514         *
    515         * @see #getBaseSeriesVisible()
    516         */
    517        public void setBaseSeriesVisible(boolean visible) {
    518            // defer argument checking...
    519            setBaseSeriesVisible(visible, true);
    520        }
    521
    522        /**
    523         * Sets the base visibility and, if requested, sends
    524         * a {@link RendererChangeEvent} to all registered listeners.
    525         *
    526         * @param visible  the visibility.
    527         * @param notify  notify listeners?
    528         *
    529         * @see #getBaseSeriesVisible()
    530         */
    531        public void setBaseSeriesVisible(boolean visible, boolean notify) {
    532            this.baseSeriesVisible = visible;
    533            if (notify) {
    534                fireChangeEvent();
    535            }
    536        }
    537
    538        // SERIES VISIBLE IN LEGEND (not yet respected by all renderers)
    539
    540        /**
    541         * Returns <code>true</code> if the series should be shown in the legend,
    542         * and <code>false</code> otherwise.
    543         *
    544         * @param series  the series index.
    545         *
    546         * @return A boolean.
    547         */
    548        public boolean isSeriesVisibleInLegend(int series) {
    549            boolean result = this.baseSeriesVisibleInLegend;
    550            if (this.seriesVisibleInLegend != null) {
    551                result = this.seriesVisibleInLegend.booleanValue();
    552            }
    553            else {
    554                Boolean b = this.seriesVisibleInLegendList.getBoolean(series);
    555                if (b != null) {
    556                    result = b.booleanValue();
    557                }
    558            }
    559            return result;
    560        }
    561
    562        /**
    563         * Returns the flag that controls the visibility of ALL series in the
    564         * legend.  This flag overrides the per series and default settings - you
    565         * must set it to <code>null</code> if you want the other settings to
    566         * apply.
    567         *
    568         * @return The flag (possibly <code>null</code>).
    569         *
    570         * @see #setSeriesVisibleInLegend(Boolean)
    571         */
    572        public Boolean getSeriesVisibleInLegend() {
    573            return this.seriesVisibleInLegend;
    574        }
    575
    576        /**
    577         * Sets the flag that controls the visibility of ALL series in the legend
    578         * and sends a {@link RendererChangeEvent} to all registered listeners.
    579         * This flag overrides the per series and default settings - you must set
    580         * it to <code>null</code> if you want the other settings to apply.
    581         *
    582         * @param visible  the flag (<code>null</code> permitted).
    583         *
    584         * @see #getSeriesVisibleInLegend()
    585         */
    586        public void setSeriesVisibleInLegend(Boolean visible) {
    587             setSeriesVisibleInLegend(visible, true);
    588        }
    589
    590        /**
    591         * Sets the flag that controls the visibility of ALL series in the legend
    592         * and sends a {@link RendererChangeEvent} to all registered listeners.
    593         * This flag overrides the per series and default settings - you must set
    594         * it to <code>null</code> if you want the other settings to apply.
    595         *
    596         * @param visible  the flag (<code>null</code> permitted).
    597         * @param notify  notify listeners?
    598         *
    599         * @see #getSeriesVisibleInLegend()
    600         */
    601        public void setSeriesVisibleInLegend(Boolean visible, boolean notify) {
    602            this.seriesVisibleInLegend = visible;
    603            if (notify) {
    604                fireChangeEvent();
    605            }
    606        }
    607
    608        /**
    609         * Returns the flag that controls whether a series is visible in the
    610         * legend.  This method returns only the "per series" settings - to
    611         * incorporate the override and base settings as well, you need to use the
    612         * {@link #isSeriesVisibleInLegend(int)} method.
    613         *
    614         * @param series  the series index (zero-based).
    615         *
    616         * @return The flag (possibly <code>null</code>).
    617         *
    618         * @see #setSeriesVisibleInLegend(int, Boolean)
    619         */
    620        public Boolean getSeriesVisibleInLegend(int series) {
    621            return this.seriesVisibleInLegendList.getBoolean(series);
    622        }
    623
    624        /**
    625         * Sets the flag that controls whether a series is visible in the legend
    626         * and sends a {@link RendererChangeEvent} to all registered listeners.
    627         *
    628         * @param series  the series index (zero-based).
    629         * @param visible  the flag (<code>null</code> permitted).
    630         *
    631         * @see #getSeriesVisibleInLegend(int)
    632         */
    633        public void setSeriesVisibleInLegend(int series, Boolean visible) {
    634            setSeriesVisibleInLegend(series, visible, true);
    635        }
    636
    637        /**
    638         * Sets the flag that controls whether a series is visible in the legend
    639         * and, if requested, sends a {@link RendererChangeEvent} to all registered
    640         * listeners.
    641         *
    642         * @param series  the series index.
    643         * @param visible  the flag (<code>null</code> permitted).
    644         * @param notify  notify listeners?
    645         *
    646         * @see #getSeriesVisibleInLegend(int)
    647         */
    648        public void setSeriesVisibleInLegend(int series, Boolean visible,
    649                                             boolean notify) {
    650            this.seriesVisibleInLegendList.setBoolean(series, visible);
    651            if (notify) {
    652                fireChangeEvent();
    653            }
    654        }
    655
    656        /**
    657         * Returns the base visibility in the legend for all series.
    658         *
    659         * @return The base visibility.
    660         *
    661         * @see #setBaseSeriesVisibleInLegend(boolean)
    662         */
    663        public boolean getBaseSeriesVisibleInLegend() {
    664            return this.baseSeriesVisibleInLegend;
    665        }
    666
    667        /**
    668         * Sets the base visibility in the legend and sends a
    669         * {@link RendererChangeEvent} to all registered listeners.
    670         *
    671         * @param visible  the flag.
    672         *
    673         * @see #getSeriesVisibleInLegend()
    674         */
    675        public void setBaseSeriesVisibleInLegend(boolean visible) {
    676            // defer argument checking...
    677            setBaseSeriesVisibleInLegend(visible, true);
    678        }
    679
    680        /**
    681         * Sets the base visibility in the legend and, if requested, sends
    682         * a {@link RendererChangeEvent} to all registered listeners.
    683         *
    684         * @param visible  the visibility.
    685         * @param notify  notify listeners?
    686         *
    687         * @see #getSeriesVisibleInLegend()
    688         */
    689        public void setBaseSeriesVisibleInLegend(boolean visible, boolean notify) {
    690            this.baseSeriesVisibleInLegend = visible;
    691            if (notify) {
    692                fireChangeEvent();
    693            }
    694        }
    695
    696        // PAINT
    697
    698        /**
    699         * Returns the paint used to fill data items as they are drawn.
    700         * <p>
    701         * The default implementation passes control to the
    702         * <code>getSeriesPaint</code> method. You can override this method if you
    703         * require different behaviour.
    704         *
    705         * @param row  the row (or series) index (zero-based).
    706         * @param column  the column (or category) index (zero-based).
    707         *
    708         * @return The paint (never <code>null</code>).
    709         */
    710        public Paint getItemPaint(int row, int column) {
    711            return getSeriesPaint(row);
    712        }
    713
    714        /**
    715         * Returns the paint used to fill an item drawn by the renderer.
    716         *
    717         * @param series  the series index (zero-based).
    718         *
    719         * @return The paint (never <code>null</code>).
    720         */
    721        public Paint getSeriesPaint(int series) {
    722
    723            // return the override, if there is one...
    724            if (this.paint != null) {
    725                return this.paint;
    726            }
    727
    728            // otherwise look up the paint list
    729            Paint seriesPaint = this.paintList.getPaint(series);
    730            if (seriesPaint == null) {
    731                DrawingSupplier supplier = getDrawingSupplier();
    732                if (supplier != null) {
    733                    seriesPaint = supplier.getNextPaint();
    734                    this.paintList.setPaint(series, seriesPaint);
    735                }
    736                else {
    737                    seriesPaint = this.basePaint;
    738                }
    739            }
    740            return seriesPaint;
    741
    742        }
    743
    744        /**
    745         * Sets the paint to be used for ALL series, and sends a
    746         * {@link RendererChangeEvent} to all registered listeners.  If this is
    747         * <code>null</code>, the renderer will use the paint for the series.
    748         *
    749         * @param paint  the paint (<code>null</code> permitted).
    750         */
    751        public void setPaint(Paint paint) {
    752            setPaint(paint, true);
    753        }
    754
    755        /**
    756         * Sets the paint to be used for all series and, if requested, sends a
    757         * {@link RendererChangeEvent} to all registered listeners.
    758         *
    759         * @param paint  the paint (<code>null</code> permitted).
    760         * @param notify  notify listeners?
    761         */
    762        public void setPaint(Paint paint, boolean notify) {
    763            this.paint = paint;
    764            if (notify) {
    765                fireChangeEvent();
    766            }
    767        }
    768
    769        /**
    770         * Sets the paint used for a series and sends a {@link RendererChangeEvent}
    771         * to all registered listeners.
    772         *
    773         * @param series  the series index (zero-based).
    774         * @param paint  the paint (<code>null</code> permitted).
    775         */
    776        public void setSeriesPaint(int series, Paint paint) {
    777            setSeriesPaint(series, paint, true);
    778        }
    779
    780        /**
    781         * Sets the paint used for a series and, if requested, sends a
    782         * {@link RendererChangeEvent} to all registered listeners.
    783         *
    784         * @param series  the series index.
    785         * @param paint  the paint (<code>null</code> permitted).
    786         * @param notify  notify listeners?
    787         */
    788        public void setSeriesPaint(int series, Paint paint, boolean notify) {
    789            this.paintList.setPaint(series, paint);
    790            if (notify) {
    791                fireChangeEvent();
    792            }
    793        }
    794
    795        /**
    796         * Returns the base paint.
    797         *
    798         * @return The base paint (never <code>null</code>).
    799         */
    800        public Paint getBasePaint() {
    801            return this.basePaint;
    802        }
    803
    804        /**
    805         * Sets the base paint and sends a {@link RendererChangeEvent} to all
    806         * registered listeners.
    807         *
    808         * @param paint  the paint (<code>null</code> not permitted).
    809         */
    810        public void setBasePaint(Paint paint) {
    811            // defer argument checking...
    812            setBasePaint(paint, true);
    813        }
    814
    815        /**
    816         * Sets the base paint and, if requested, sends a
    817         * {@link RendererChangeEvent} to all registered listeners.
    818         *
    819         * @param paint  the paint (<code>null</code> not permitted).
    820         * @param notify  notify listeners?
    821         */
    822        public void setBasePaint(Paint paint, boolean notify) {
    823            this.basePaint = paint;
    824            if (notify) {
    825                fireChangeEvent();
    826            }
    827        }
    828
    829        //// FILL PAINT //////////////////////////////////////////////////////////
    830
    831        /**
    832         * Returns the paint used to fill data items as they are drawn.  The
    833         * default implementation passes control to the
    834         * {@link #getSeriesFillPaint(int)} method - you can override this method
    835         * if you require different behaviour.
    836         *
    837         * @param row  the row (or series) index (zero-based).
    838         * @param column  the column (or category) index (zero-based).
    839         *
    840         * @return The paint (never <code>null</code>).
    841         */
    842        public Paint getItemFillPaint(int row, int column) {
    843            return getSeriesFillPaint(row);
    844        }
    845
    846        /**
    847         * Returns the paint used to fill an item drawn by the renderer.
    848         *
    849         * @param series  the series (zero-based index).
    850         *
    851         * @return The paint (never <code>null</code>).
    852         */
    853        public Paint getSeriesFillPaint(int series) {
    854
    855            // return the override, if there is one...
    856            if (this.fillPaint != null) {
    857                return this.fillPaint;
    858            }
    859
    860            // otherwise look up the paint table
    861            Paint seriesFillPaint = this.fillPaintList.getPaint(series);
    862            if (seriesFillPaint == null) {
    863                seriesFillPaint = this.baseFillPaint;
    864            }
    865            return seriesFillPaint;
    866
    867        }
    868
    869        /**
    870         * Sets the paint used for a series fill and sends a
    871         * {@link RendererChangeEvent} to all registered listeners.
    872         *
    873         * @param series  the series index (zero-based).
    874         * @param paint  the paint (<code>null</code> permitted).
    875         */
    876        public void setSeriesFillPaint(int series, Paint paint) {
    877            setSeriesFillPaint(series, paint, true);
    878        }
    879
    880        /**
    881         * Sets the paint used to fill a series and, if requested,
    882         * sends a {@link RendererChangeEvent} to all registered listeners.
    883         *
    884         * @param series  the series index (zero-based).
    885         * @param paint  the paint (<code>null</code> permitted).
    886         * @param notify  notify listeners?
    887         */
    888        public void setSeriesFillPaint(int series, Paint paint, boolean notify) {
    889            this.fillPaintList.setPaint(series, paint);
    890            if (notify) {
    891                fireChangeEvent();
    892            }
    893        }
    894
    895        /**
    896         * Sets the fill paint for ALL series (optional).
    897         *
    898         * @param paint  the paint (<code>null</code> permitted).
    899         */
    900        public void setFillPaint(Paint paint) {
    901            setFillPaint(paint, true);
    902        }
    903
    904        /**
    905         * Sets the fill paint for ALL series and, if requested, sends a
    906         * {@link RendererChangeEvent} to all registered listeners.
    907         *
    908         * @param paint  the paint (<code>null</code> permitted).
    909         * @param notify  notify listeners?
    910         */
    911        public void setFillPaint(Paint paint, boolean notify) {
    912            this.fillPaint = paint;
    913            if (notify) {
    914                fireChangeEvent();
    915            }
    916        }
    917
    918        /**
    919         * Returns the base fill paint.
    920         *
    921         * @return The paint (never <code>null</code>).
    922         */
    923        public Paint getBaseFillPaint() {
    924            return this.baseFillPaint;
    925        }
    926
    927        /**
    928         * Sets the base fill paint and sends a {@link RendererChangeEvent} to
    929         * all registered listeners.
    930         *
    931         * @param paint  the paint (<code>null</code> not permitted).
    932         */
    933        public void setBaseFillPaint(Paint paint) {
    934            // defer argument checking...
    935            setBaseFillPaint(paint, true);
    936        }
    937
    938        /**
    939         * Sets the base fill paint and, if requested, sends a
    940         * {@link RendererChangeEvent} to all registered listeners.
    941         *
    942         * @param paint  the paint (<code>null</code> not permitted).
    943         * @param notify  notify listeners?
    944         */
    945        public void setBaseFillPaint(Paint paint, boolean notify) {
    946            if (paint == null) {
    947                throw new IllegalArgumentException("Null 'paint' argument.");
    948            }
    949            this.baseFillPaint = paint;
    950            if (notify) {
    951                fireChangeEvent();
    952            }
    953        }
    954
    955        // OUTLINE PAINT //////////////////////////////////////////////////////////
    956
    957        /**
    958         * Returns the paint used to outline data items as they are drawn.
    959         * <p>
    960         * The default implementation passes control to the getSeriesOutlinePaint
    961         * method.  You can override this method if you require different behaviour.
    962         *
    963         * @param row  the row (or series) index (zero-based).
    964         * @param column  the column (or category) index (zero-based).
    965         *
    966         * @return The paint (never <code>null</code>).
    967         */
    968        public Paint getItemOutlinePaint(int row, int column) {
    969            return getSeriesOutlinePaint(row);
    970        }
    971
    972        /**
    973         * Returns the paint used to outline an item drawn by the renderer.
    974         *
    975         * @param series  the series (zero-based index).
    976         *
    977         * @return The paint (never <code>null</code>).
    978         */
    979        public Paint getSeriesOutlinePaint(int series) {
    980
    981            // return the override, if there is one...
    982            if (this.outlinePaint != null) {
    983                return this.outlinePaint;
    984            }
    985
    986            // otherwise look up the paint table
    987            Paint seriesOutlinePaint = this.outlinePaintList.getPaint(series);
    988            if (seriesOutlinePaint == null) {
    989                DrawingSupplier supplier = getDrawingSupplier();
    990                if (supplier != null) {
    991                    seriesOutlinePaint = supplier.getNextOutlinePaint();
    992                    this.outlinePaintList.setPaint(series, seriesOutlinePaint);
    993                }
    994                else {
    995                    seriesOutlinePaint = this.baseOutlinePaint;
    996                }
    997            }
    998            return seriesOutlinePaint;
    999
    1000        }
    1001
    1002        /**
    1003         * Sets the paint used for a series outline and sends a
    1004         * {@link RendererChangeEvent} to all registered listeners.
    1005         *
    1006         * @param series  the series index (zero-based).
    1007         * @param paint  the paint (<code>null</code> permitted).
    1008         */
    1009        public void setSeriesOutlinePaint(int series, Paint paint) {
    1010            setSeriesOutlinePaint(series, paint, true);
    1011        }
    1012
    1013        /**
    1014         * Sets the paint used to draw the outline for a series and, if requested,
    1015         * sends a {@link RendererChangeEvent} to all registered listeners.
    1016         *
    1017         * @param series  the series index (zero-based).
    1018         * @param paint  the paint (<code>null</code> permitted).
    1019         * @param notify  notify listeners?
    1020         */
    1021        public void setSeriesOutlinePaint(int series, Paint paint, boolean notify) {
    1022            this.outlinePaintList.setPaint(series, paint);
    1023            if (notify) {
    1024                fireChangeEvent();
    1025            }
    1026        }
    1027
    1028        /**
    1029         * Sets the outline paint for ALL series (optional).
    1030         *
    1031         * @param paint  the paint (<code>null</code> permitted).
    1032         */
    1033        public void setOutlinePaint(Paint paint) {
    1034            setOutlinePaint(paint, true);
    1035        }
    1036
    1037        /**
    1038         * Sets the outline paint for ALL series and, if requested, sends a
    1039         * {@link RendererChangeEvent} to all registered listeners.
    1040         *
    1041         * @param paint  the paint (<code>null</code> permitted).
    1042         * @param notify  notify listeners?
    1043         */
    1044        public void setOutlinePaint(Paint paint, boolean notify) {
    1045            this.outlinePaint = paint;
    1046            if (notify) {
    1047                fireChangeEvent();
    1048            }
    1049        }
    1050
    1051        /**
    1052         * Returns the base outline paint.
    1053         *
    1054         * @return The paint (never <code>null</code>).
    1055         */
    1056        public Paint getBaseOutlinePaint() {
    1057            return this.baseOutlinePaint;
    1058        }
    1059
    1060        /**
    1061         * Sets the base outline paint and sends a {@link RendererChangeEvent} to
    1062         * all registered listeners.
    1063         *
    1064         * @param paint  the paint (<code>null</code> not permitted).
    1065         */
    1066        public void setBaseOutlinePaint(Paint paint) {
    1067            // defer argument checking...
    1068            setBaseOutlinePaint(paint, true);
    1069        }
    1070
    1071        /**
    1072         * Sets the base outline paint and, if requested, sends a
    1073         * {@link RendererChangeEvent} to all registered listeners.
    1074         *
    1075         * @param paint  the paint (<code>null</code> not permitted).
    1076         * @param notify  notify listeners?
    1077         */
    1078        public void setBaseOutlinePaint(Paint paint, boolean notify) {
    1079            if (paint == null) {
    1080                throw new IllegalArgumentException("Null 'paint' argument.");
    1081            }
    1082            this.baseOutlinePaint = paint;
    1083            if (notify) {
    1084                fireChangeEvent();
    1085            }
    1086        }
    1087
    1088        // STROKE
    1089
    1090        /**
    1091         * Returns the stroke used to draw data items.
    1092         * <p>
    1093         * The default implementation passes control to the getSeriesStroke method.
    1094         * You can override this method if you require different behaviour.
    1095         *
    1096         * @param row  the row (or series) index (zero-based).
    1097         * @param column  the column (or category) index (zero-based).
    1098         *
    1099         * @return The stroke (never <code>null</code>).
    1100         */
    1101        public Stroke getItemStroke(int row, int column) {
    1102            return getSeriesStroke(row);
    1103        }
    1104
    1105        /**
    1106         * Returns the stroke used to draw the items in a series.
    1107         *
    1108         * @param series  the series (zero-based index).
    1109         *
    1110         * @return The stroke (never <code>null</code>).
    1111         */
    1112        public Stroke getSeriesStroke(int series) {
    1113
    1114            // return the override, if there is one...
    1115            if (this.stroke != null) {
    1116                return this.stroke;
    1117            }
    1118
    1119            // otherwise look up the paint table
    1120            Stroke result = this.strokeList.getStroke(series);
    1121            if (result == null) {
    1122                DrawingSupplier supplier = getDrawingSupplier();
    1123                if (supplier != null) {
    1124                    result = supplier.getNextStroke();
    1125                    this.strokeList.setStroke(series, result);
    1126                }
    1127                else {
    1128                    result = this.baseStroke;
    1129                }
    1130            }
    1131            return result;
    1132
    1133        }
    1134
    1135        /**
    1136         * Sets the stroke for ALL series and sends a {@link RendererChangeEvent}
    1137         * to all registered listeners.
    1138         *
    1139         * @param stroke  the stroke (<code>null</code> permitted).
    1140         */
    1141        public void setStroke(Stroke stroke) {
    1142            setStroke(stroke, true);
    1143        }
    1144
    1145        /**
    1146         * Sets the stroke for ALL series and, if requested, sends a
    1147         * {@link RendererChangeEvent} to all registered listeners.
    1148         *
    1149         * @param stroke  the stroke (<code>null</code> permitted).
    1150         * @param notify  notify listeners?
    1151         */
    1152        public void setStroke(Stroke stroke, boolean notify) {
    1153            this.stroke = stroke;
    1154            if (notify) {
    1155                fireChangeEvent();
    1156            }
    1157        }
    1158
    1159        /**
    1160         * Sets the stroke used for a series and sends a {@link RendererChangeEvent}
    1161         * to all registered listeners.
    1162         *
    1163         * @param series  the series index (zero-based).
    1164         * @param stroke  the stroke (<code>null</code> permitted).
    1165         */
    1166        public void setSeriesStroke(int series, Stroke stroke) {
    1167            setSeriesStroke(series, stroke, true);
    1168        }
    1169
    1170        /**
    1171         * Sets the stroke for a series and, if requested, sends a
    1172         * {@link RendererChangeEvent} to all registered listeners.
    1173         *
    1174         * @param series  the series index (zero-based).
    1175         * @param stroke  the stroke (<code>null</code> permitted).
    1176         * @param notify  notify listeners?
    1177         */
    1178        public void setSeriesStroke(int series, Stroke stroke, boolean notify) {
    1179            this.strokeList.setStroke(series, stroke);
    1180            if (notify) {
    1181                fireChangeEvent();
    1182            }
    1183        }
    1184
    1185        /**
    1186         * Returns the base stroke.
    1187         *
    1188         * @return The base stroke (never <code>null</code>).
    1189         */
    1190        public Stroke getBaseStroke() {
    1191            return this.baseStroke;
    1192        }
    1193
    1194        /**
    1195         * Sets the base stroke.
    1196         *
    1197         * @param stroke  the stroke (<code>null</code> not permitted).
    1198         */
    1199        public void setBaseStroke(Stroke stroke) {
    1200            // defer argument checking...
    1201            setBaseStroke(stroke, true);
    1202        }
    1203
    1204        /**
    1205         * Sets the base stroke and, if requested, sends a
    1206         * {@link RendererChangeEvent} to all registered listeners.
    1207         *
    1208         * @param stroke  the stroke (<code>null</code> not permitted).
    1209         * @param notify  notify listeners?
    1210         */
    1211        public void setBaseStroke(Stroke stroke, boolean notify) {
    1212            if (stroke == null) {
    1213                throw new IllegalArgumentException("Null 'stroke' argument.");
    1214            }
    1215            this.baseStroke = stroke;
    1216            if (notify) {
    1217                fireChangeEvent();
    1218            }
    1219        }
    1220
    1221        // OUTLINE STROKE
    1222
    1223        /**
    1224         * Returns the stroke used to outline data items.  The default
    1225         * implementation passes control to the {@link #getSeriesOutlineStroke(int)}
    1226         * method. You can override this method if you require different behaviour.
    1227         *
    1228         * @param row  the row (or series) index (zero-based).
    1229         * @param column  the column (or category) index (zero-based).
    1230         *
    1231         * @return The stroke (never <code>null</code>).
    1232         */
    1233        public Stroke getItemOutlineStroke(int row, int column) {
    1234            return getSeriesOutlineStroke(row);
    1235        }
    1236
    1237        /**
    1238         * Returns the stroke used to outline the items in a series.
    1239         *
    1240         * @param series  the series (zero-based index).
    1241         *
    1242         * @return The stroke (never <code>null</code>).
    1243         */
    1244        public Stroke getSeriesOutlineStroke(int series) {
    1245
    1246            // return the override, if there is one...
    1247            if (this.outlineStroke != null) {
    1248                return this.outlineStroke;
    1249            }
    1250
    1251            // otherwise look up the stroke table
    1252            Stroke result = this.outlineStrokeList.getStroke(series);
    1253            if (result == null) {
    1254                DrawingSupplier supplier = getDrawingSupplier();
    1255                if (supplier != null) {
    1256                    result = supplier.getNextOutlineStroke();
    1257                    this.outlineStrokeList.setStroke(series, result);
    1258                }
    1259                else {
    1260                    result = this.baseOutlineStroke;
    1261                }
    1262            }
    1263            return result;
    1264
    1265        }
    1266
    1267        /**
    1268         * Sets the outline stroke for ALL series and sends a
    1269         * {@link RendererChangeEvent} to all registered listeners.
    1270         *
    1271         * @param stroke  the stroke (<code>null</code> permitted).
    1272         */
    1273        public void setOutlineStroke(Stroke stroke) {
    1274            setOutlineStroke(stroke, true);
    1275        }
    1276
    1277        /**
    1278         * Sets the outline stroke for ALL series and, if requested, sends a
    1279         * {@link RendererChangeEvent} to all registered listeners.
    1280         *
    1281         * @param stroke  the stroke (<code>null</code> permitted).
    1282         * @param notify  notify listeners?
    1283         */
    1284        public void setOutlineStroke(Stroke stroke, boolean notify) {
    1285            this.outlineStroke = stroke;
    1286            if (notify) {
    1287                fireChangeEvent();
    1288            }
    1289        }
    1290
    1291        /**
    1292         * Sets the outline stroke used for a series and sends a
    1293         * {@link RendererChangeEvent} to all registered listeners.
    1294         *
    1295         * @param series  the series index (zero-based).
    1296         * @param stroke  the stroke (<code>null</code> permitted).
    1297         */
    1298        public void setSeriesOutlineStroke(int series, Stroke stroke) {
    1299            setSeriesOutlineStroke(series, stroke, true);
    1300        }
    1301
    1302        /**
    1303         * Sets the outline stroke for a series and, if requested, sends a
    1304         * {@link RendererChangeEvent} to all registered listeners.
    1305         *
    1306         * @param series  the series index.
    1307         * @param stroke  the stroke (<code>null</code> permitted).
    1308         * @param notify  notify listeners?
    1309         */
    1310        public void setSeriesOutlineStroke(int series, Stroke stroke,
    1311                                           boolean notify) {
    1312            this.outlineStrokeList.setStroke(series, stroke);
    1313            if (notify) {
    1314                fireChangeEvent();
    1315            }
    1316        }
    1317
    1318        /**
    1319         * Returns the base outline stroke.
    1320         *
    1321         * @return The stroke (never <code>null</code>).
    1322         */
    1323        public Stroke getBaseOutlineStroke() {
    1324            return this.baseOutlineStroke;
    1325        }
    1326
    1327        /**
    1328         * Sets the base outline stroke and sends a {@link RendererChangeEvent} to
    1329         * all registered listeners.
    1330         *
    1331         * @param stroke  the stroke (<code>null</code> not permitted).
    1332         */
    1333        public void setBaseOutlineStroke(Stroke stroke) {
    1334            setBaseOutlineStroke(stroke, true);
    1335        }
    1336
    1337        /**
    1338         * Sets the base outline stroke and, if requested, sends a
    1339         * {@link RendererChangeEvent} to all registered listeners.
    1340         *
    1341         * @param stroke  the stroke (<code>null</code> not permitted).
    1342         * @param notify  a flag that controls whether or not listeners are
    1343         *                notified.
    1344         */
    1345        public void setBaseOutlineStroke(Stroke stroke, boolean notify) {
    1346            if (stroke == null) {
    1347                throw new IllegalArgumentException("Null 'stroke' argument.");
    1348            }
    1349            this.baseOutlineStroke = stroke;
    1350            if (notify) {
    1351                fireChangeEvent();
    1352            }
    1353        }
    1354
    1355        // SHAPE
    1356
    1357        /**
    1358         * Returns a shape used to represent a data item.
    1359         * <p>
    1360         * The default implementation passes control to the getSeriesShape method.
    1361         * You can override this method if you require different behaviour.
    1362         *
    1363         * @param row  the row (or series) index (zero-based).
    1364         * @param column  the column (or category) index (zero-based).
    1365         *
    1366         * @return The shape (never <code>null</code>).
    1367         */
    1368        public Shape getItemShape(int row, int column) {
    1369            return getSeriesShape(row);
    1370        }
    1371
    1372        /**
    1373         * Returns a shape used to represent the items in a series.
    1374         *
    1375         * @param series  the series (zero-based index).
    1376         *
    1377         * @return The shape (never <code>null</code>).
    1378         */
    1379        public Shape getSeriesShape(int series) {
    1380
    1381            // return the override, if there is one...
    1382            if (this.shape != null) {
    1383                return this.shape;
    1384            }
    1385
    1386            // otherwise look up the shape list
    1387            Shape result = this.shapeList.getShape(series);
    1388            if (result == null) {
    1389                DrawingSupplier supplier = getDrawingSupplier();
    1390                if (supplier != null) {
    1391                    result = supplier.getNextShape();
    1392                    this.shapeList.setShape(series, result);
    1393                }
    1394                else {
    1395                    result = this.baseShape;
    1396                }
    1397            }
    1398            return result;
    1399
    1400        }
    1401
    1402        /**
    1403         * Sets the shape for ALL series (optional) and sends a
    1404         * {@link RendererChangeEvent} to all registered listeners.
    1405         *
    1406         * @param shape  the shape (<code>null</code> permitted).
    1407         */
    1408        public void setShape(Shape shape) {
    1409            setShape(shape, true);
    1410        }
    1411
    1412        /**
    1413         * Sets the shape for ALL series and, if requested, sends a
    1414         * {@link RendererChangeEvent} to all registered listeners.
    1415         *
    1416         * @param shape  the shape (<code>null</code> permitted).
    1417         * @param notify  notify listeners?
    1418         */
    1419        public void setShape(Shape shape, boolean notify) {
    1420            this.shape = shape;
    1421            if (notify) {
    1422                fireChangeEvent();
    1423            }
    1424        }
    1425
    1426        /**
    1427         * Sets the shape used for a series and sends a {@link RendererChangeEvent}
    1428         * to all registered listeners.
    1429         *
    1430         * @param series  the series index (zero-based).
    1431         * @param shape  the shape (<code>null</code> permitted).
    1432         */
    1433        public void setSeriesShape(int series, Shape shape) {
    1434            setSeriesShape(series, shape, true);
    1435        }
    1436
    1437        /**
    1438         * Sets the shape for a series and, if requested, sends a
    1439         * {@link RendererChangeEvent} to all registered listeners.
    1440         *
    1441         * @param series  the series index (zero based).
    1442         * @param shape  the shape (<code>null</code> permitted).
    1443         * @param notify  notify listeners?
    1444         */
    1445        public void setSeriesShape(int series, Shape shape, boolean notify) {
    1446            this.shapeList.setShape(series, shape);
    1447            if (notify) {
    1448                fireChangeEvent();
    1449            }
    1450        }
    1451
    1452        /**
    1453         * Returns the base shape.
    1454         *
    1455         * @return The shape (never <code>null</code>).
    1456         */
    1457        public Shape getBaseShape() {
    1458            return this.baseShape;
    1459        }
    1460
    1461        /**
    1462         * Sets the base shape and sends a {@link RendererChangeEvent} to all
    1463         * registered listeners.
    1464         *
    1465         * @param shape  the shape (<code>null</code> not permitted).
    1466         */
    1467        public void setBaseShape(Shape shape) {
    1468            // defer argument checking...
    1469            setBaseShape(shape, true);
    1470        }
    1471
    1472        /**
    1473         * Sets the base shape and, if requested, sends a
    1474         * {@link RendererChangeEvent} to all registered listeners.
    1475         *
    1476         * @param shape  the shape (<code>null</code> not permitted).
    1477         * @param notify  notify listeners?
    1478         */
    1479        public void setBaseShape(Shape shape, boolean notify) {
    1480            if (shape == null) {
    1481                throw new IllegalArgumentException("Null 'shape' argument.");
    1482            }
    1483            this.baseShape = shape;
    1484            if (notify) {
    1485                fireChangeEvent();
    1486            }
    1487        }
    1488
    1489        // ITEM LABEL VISIBILITY...
    1490
    1491        /**
    1492         * Returns <code>true</code> if an item label is visible, and
    1493         * <code>false</code> otherwise.
    1494         *
    1495         * @param row  the row index (zero-based).
    1496         * @param column  the column index (zero-based).
    1497         *
    1498         * @return A boolean.
    1499         */
    1500        public boolean isItemLabelVisible(int row, int column) {
    1501            return isSeriesItemLabelsVisible(row);
    1502        }
    1503
    1504        /**
    1505         * Returns <code>true</code> if the item labels for a series are visible,
    1506         * and <code>false</code> otherwise.
    1507         *
    1508         * @param series  the series index (zero-based).
    1509         *
    1510         * @return A boolean.
    1511         */
    1512        public boolean isSeriesItemLabelsVisible(int series) {
    1513
    1514            // return the override, if there is one...
    1515            if (this.itemLabelsVisible != null) {
    1516                return this.itemLabelsVisible.booleanValue();
    1517            }
    1518
    1519            // otherwise look up the boolean table
    1520            Boolean b = this.itemLabelsVisibleList.getBoolean(series);
    1521            if (b == null) {
    1522                b = this.baseItemLabelsVisible;
    1523            }
    1524            if (b == null) {
    1525                b = Boolean.FALSE;
    1526            }
    1527            return b.booleanValue();
    1528
    1529        }
    1530
    1531        /**
    1532         * Sets the visibility of the item labels for ALL series.
    1533         *
    1534         * @param visible  the flag.
    1535         */
    1536        public void setItemLabelsVisible(boolean visible) {
    1537            setItemLabelsVisible(BooleanUtilities.valueOf(visible));
    1538            // The following alternative is only supported in JDK 1.4 - we support
    1539            // JDK 1.2.2
    1540            // setItemLabelsVisible(Boolean.valueOf(visible));
    1541        }
    1542
    1543        /**
    1544         * Sets the visibility of the item labels for ALL series (optional).
    1545         *
    1546         * @param visible  the flag (<code>null</code> permitted).
    1547         */
    1548        public void setItemLabelsVisible(Boolean visible) {
    1549            setItemLabelsVisible(visible, true);
    1550        }
    1551
    1552        /**
    1553         * Sets the visibility of item labels for ALL series and, if requested,
    1554         * sends a {@link RendererChangeEvent} to all registered listeners.
    1555         *
    1556         * @param visible  a flag that controls whether or not the item labels are
    1557         *                 visible (<code>null</code> permitted).
    1558         * @param notify  a flag that controls whether or not listeners are
    1559         *                notified.
    1560         */
    1561        public void setItemLabelsVisible(Boolean visible, boolean notify) {
    1562            this.itemLabelsVisible = visible;
    1563            if (notify) {
    1564                fireChangeEvent();
    1565            }
    1566        }
    1567
    1568        /**
    1569         * Sets a flag that controls the visibility of the item labels for a series.
    1570         *
    1571         * @param series  the series index (zero-based).
    1572         * @param visible  the flag.
    1573         */
    1574        public void setSeriesItemLabelsVisible(int series, boolean visible) {
    1575            setSeriesItemLabelsVisible(series, BooleanUtilities.valueOf(visible));
    1576        }
    1577
    1578        /**
    1579         * Sets the visibility of the item labels for a series.
    1580         *
    1581         * @param series  the series index (zero-based).
    1582         * @param visible  the flag (<code>null</code> permitted).
    1583         */
    1584        public void setSeriesItemLabelsVisible(int series, Boolean visible) {
    1585            setSeriesItemLabelsVisible(series, visible, true);
    1586        }
    1587
    1588        /**
    1589         * Sets the visibility of item labels for a series and, if requested, sends
    1590         * a {@link RendererChangeEvent} to all registered listeners.
    1591         *
    1592         * @param series  the series index (zero-based).
    1593         * @param visible  the visible flag.
    1594         * @param notify  a flag that controls whether or not listeners are
    1595         *                notified.
    1596         */
    1597        public void setSeriesItemLabelsVisible(int series, Boolean visible,
    1598                                               boolean notify) {
    1599            this.itemLabelsVisibleList.setBoolean(series, visible);
    1600            if (notify) {
    1601                fireChangeEvent();
    1602            }
    1603        }
    1604
    1605        /**
    1606         * Returns the base setting for item label visibility.  A <code>null</code>
    1607         * result should be interpreted as equivalent to <code>Boolean.FALSE</code>.
    1608         *
    1609         * @return A flag (possibly <code>null</code>).
    1610         */
    1611        public Boolean getBaseItemLabelsVisible() {
    1612            // this should have been defined as a boolean primitive, because
    1613            // allowing null values is a nuisance...but it is part of the final
    1614            // API now, so we'll have to support it.
    1615            return this.baseItemLabelsVisible;
    1616        }
    1617
    1618        /**
    1619         * Sets the base flag that controls whether or not item labels are visible.
    1620         *
    1621         * @param visible  the flag.
    1622         */
    1623        public void setBaseItemLabelsVisible(boolean visible) {
    1624            setBaseItemLabelsVisible(BooleanUtilities.valueOf(visible));
    1625        }
    1626
    1627        /**
    1628         * Sets the base setting for item label visibility.
    1629         *
    1630         * @param visible  the flag (<code>null</code> is permitted, and viewed
    1631         *     as equivalent to <code>Boolean.FALSE</code>).
    1632         */
    1633        public void setBaseItemLabelsVisible(Boolean visible) {
    1634            setBaseItemLabelsVisible(visible, true);
    1635        }
    1636
    1637        /**
    1638         * Sets the base visibility for item labels and, if requested, sends a
    1639         * {@link RendererChangeEvent} to all registered listeners.
    1640         *
    1641         * @param visible  the flag (<code>null</code> is permitted, and viewed
    1642         *     as equivalent to <code>Boolean.FALSE</code>).
    1643         * @param notify  a flag that controls whether or not listeners are
    1644         *                notified.
    1645         */
    1646        public void setBaseItemLabelsVisible(Boolean visible, boolean notify) {
    1647            this.baseItemLabelsVisible = visible;
    1648            if (notify) {
    1649                fireChangeEvent();
    1650            }
    1651        }
    1652
    1653        //// ITEM LABEL FONT //////////////////////////////////////////////////////
    1654
    1655        /**
    1656         * Returns the font for an item label.
    1657         *
    1658         * @param row  the row index (zero-based).
    1659         * @param column  the column index (zero-based).
    1660         *
    1661         * @return The font (never <code>null</code>).
    1662         */
    1663        public Font getItemLabelFont(int row, int column) {
    1664            Font result = this.itemLabelFont;
    1665            if (result == null) {
    1666                result = getSeriesItemLabelFont(row);
    1667                if (result == null) {
    1668                    result = this.baseItemLabelFont;
    1669                }
    1670            }
    1671            return result;
    1672        }
    1673
    1674        /**
    1675         * Returns the font used for all item labels.  This may be
    1676         * <code>null</code>, in which case the per series font settings will apply.
    1677         *
    1678         * @return The font (possibly <code>null</code>).
    1679         */
    1680        public Font getItemLabelFont() {
    1681            return this.itemLabelFont;
    1682        }
    1683
    1684        /**
    1685         * Sets the item label font for ALL series and sends a
    1686         * {@link RendererChangeEvent} to all registered listeners.  You can set
    1687         * this to <code>null</code> if you prefer to set the font on a per series
    1688         * basis.
    1689         *
    1690         * @param font  the font (<code>null</code> permitted).
    1691         */
    1692        public void setItemLabelFont(Font font) {
    1693            setItemLabelFont(font, true);
    1694        }
    1695
    1696        /**
    1697         * Sets the item label font for ALL series and, if requested, sends a
    1698         * {@link RendererChangeEvent} to all registered listeners.
    1699         *
    1700         * @param font  the font (<code>null</code> permitted).
    1701         * @param notify  a flag that controls whether or not listeners are
    1702         *                notified.
    1703         */
    1704        public void setItemLabelFont(Font font, boolean notify) {
    1705            this.itemLabelFont = font;
    1706            if (notify) {
    1707                fireChangeEvent();
    1708            }
    1709        }
    1710
    1711        /**
    1712         * Returns the font for all the item labels in a series.
    1713         *
    1714         * @param series  the series index (zero-based).
    1715         *
    1716         * @return The font (possibly <code>null</code>).
    1717         */
    1718        public Font getSeriesItemLabelFont(int series) {
    1719            return (Font) this.itemLabelFontList.get(series);
    1720        }
    1721
    1722        /**
    1723         * Sets the item label font for a series and sends a
    1724         * {@link RendererChangeEvent} to all registered listeners.
    1725         *
    1726         * @param series  the series index (zero-based).
    1727         * @param font  the font (<code>null</code> permitted).
    1728         */
    1729        public void setSeriesItemLabelFont(int series, Font font) {
    1730            setSeriesItemLabelFont(series, font, true);
    1731        }
    1732
    1733        /**
    1734         * Sets the item label font for a series and, if requested, sends a
    1735         * {@link RendererChangeEvent} to all registered listeners.
    1736         *
    1737         * @param series  the series index (zero based).
    1738         * @param font  the font (<code>null</code> permitted).
    1739         * @param notify  a flag that controls whether or not listeners are
    1740         *                notified.
    1741         */
    1742        public void setSeriesItemLabelFont(int series, Font font, boolean notify) {
    1743            this.itemLabelFontList.set(series, font);
    1744            if (notify) {
    1745                fireChangeEvent();
    1746            }
    1747        }
    1748
    1749        /**
    1750         * Returns the base item label font (this is used when no other font
    1751         * setting is available).
    1752         *
    1753         * @return The font (<code>never</code> null).
    1754         */
    1755        public Font getBaseItemLabelFont() {
    1756            return this.baseItemLabelFont;
    1757        }
    1758
    1759        /**
    1760         * Sets the base item label font and sends a {@link RendererChangeEvent} to
    1761         * all registered listeners.
    1762         *
    1763         * @param font  the font (<code>null</code> not permitted).
    1764         */
    1765        public void setBaseItemLabelFont(Font font) {
    1766            if (font == null) {
    1767                throw new IllegalArgumentException("Null 'font' argument.");
    1768            }
    1769            setBaseItemLabelFont(font, true);
    1770        }
    1771
    1772        /**
    1773         * Sets the base item label font and, if requested, sends a
    1774         * {@link RendererChangeEvent} to all registered listeners.
    1775         *
    1776         * @param font  the font (<code>null</code> not permitted).
    1777         * @param notify  a flag that controls whether or not listeners are
    1778         *                notified.
    1779         */
    1780        public void setBaseItemLabelFont(Font font, boolean notify) {
    1781            this.baseItemLabelFont = font;
    1782            if (notify) {
    1783                fireChangeEvent();
    1784            }
    1785        }
    1786
    1787        //// ITEM LABEL PAINT  ////////////////////////////////////////////////////
    1788
    1789        /**
    1790         * Returns the paint used to draw an item label.
    1791         *
    1792         * @param row  the row index (zero based).
    1793         * @param column  the column index (zero based).
    1794         *
    1795         * @return The paint (never <code>null</code>).
    1796         */
    1797        public Paint getItemLabelPaint(int row, int column) {
    1798            Paint result = this.itemLabelPaint;
    1799            if (result == null) {
    1800                result = getSeriesItemLabelPaint(row);
    1801                if (result == null) {
    1802                    result = this.baseItemLabelPaint;
    1803                }
    1804            }
    1805            return result;
    1806        }
    1807
    1808        /**
    1809         * Returns the paint used for all item labels.  This may be
    1810         * <code>null</code>, in which case the per series paint settings will
    1811         * apply.
    1812         *
    1813         * @return The paint (possibly <code>null</code>).
    1814         */
    1815        public Paint getItemLabelPaint() {
    1816            return this.itemLabelPaint;
    1817        }
    1818
    1819        /**
    1820         * Sets the item label paint for ALL series and sends a
    1821         * {@link RendererChangeEvent} to all registered listeners.
    1822         *
    1823         * @param paint  the paint (<code>null</code> permitted).
    1824         */
    1825        public void setItemLabelPaint(Paint paint) {
    1826            setItemLabelPaint(paint, true);
    1827        }
    1828
    1829        /**
    1830         * Sets the item label paint for ALL series and, if requested, sends a
    1831         * {@link RendererChangeEvent} to all registered listeners.
    1832         *
    1833         * @param paint  the paint.
    1834         * @param notify  a flag that controls whether or not listeners are
    1835         *                notified.
    1836         */
    1837        public void setItemLabelPaint(Paint paint, boolean notify) {
    1838            this.itemLabelPaint = paint;
    1839            if (notify) {
    1840                fireChangeEvent();
    1841            }
    1842        }
    1843
    1844        /**
    1845         * Returns the paint used to draw the item labels for a series.
    1846         *
    1847         * @param series  the series index (zero based).
    1848         *
    1849         * @return The paint (possibly <code>null<code>).
    1850         */
    1851        public Paint getSeriesItemLabelPaint(int series) {
    1852            return this.itemLabelPaintList.getPaint(series);
    1853        }
    1854
    1855        /**
    1856         * Sets the item label paint for a series and sends a
    1857         * {@link RendererChangeEvent} to all registered listeners.
    1858         *
    1859         * @param series  the series (zero based index).
    1860         * @param paint  the paint (<code>null</code> permitted).
    1861         */
    1862        public void setSeriesItemLabelPaint(int series, Paint paint) {
    1863            setSeriesItemLabelPaint(series, paint, true);
    1864        }
    1865
    1866        /**
    1867         * Sets the item label paint for a series and, if requested, sends a
    1868         * {@link RendererChangeEvent} to all registered listeners.
    1869         *
    1870         * @param series  the series index (zero based).
    1871         * @param paint  the paint (<code>null</code> permitted).
    1872         * @param notify  a flag that controls whether or not listeners are
    1873         *                notified.
    1874         */
    1875        public void setSeriesItemLabelPaint(int series, Paint paint,
    1876                                            boolean notify) {
    1877            this.itemLabelPaintList.setPaint(series, paint);
    1878            if (notify) {
    1879                fireChangeEvent();
    1880            }
    1881        }
    1882
    1883        /**
    1884         * Returns the base item label paint.
    1885         *
    1886         * @return The paint (never <code>null<code>).
    1887         */
    1888        public Paint getBaseItemLabelPaint() {
    1889            return this.baseItemLabelPaint;
    1890        }
    1891
    1892        /**
    1893         * Sets the base item label paint and sends a {@link RendererChangeEvent}
    1894         * to all registered listeners.
    1895         *
    1896         * @param paint  the paint (<code>null</code> not permitted).
    1897         */
    1898        public void setBaseItemLabelPaint(Paint paint) {
    1899            // defer argument checking...
    1900            setBaseItemLabelPaint(paint, true);
    1901        }
    1902
    1903        /**
    1904         * Sets the base item label paint and, if requested, sends a
    1905         * {@link RendererChangeEvent} to all registered listeners..
    1906         *
    1907         * @param paint  the paint (<code>null</code> not permitted).
    1908         * @param notify  a flag that controls whether or not listeners are
    1909         *                notified.
    1910         */
    1911        public void setBaseItemLabelPaint(Paint paint, boolean notify) {
    1912            if (paint == null) {
    1913                throw new IllegalArgumentException("Null 'paint' argument.");
    1914            }
    1915            this.baseItemLabelPaint = paint;
    1916            if (notify) {
    1917                fireChangeEvent();
    1918            }
    1919        }
    1920
    1921        // POSITIVE ITEM LABEL POSITION...
    1922
    1923        /**
    1924         * Returns the item label position for positive values.
    1925         *
    1926         * @param row  the row index (zero-based).
    1927         * @param column  the column index (zero-based).
    1928         *
    1929         * @return The item label position (never <code>null</code>).
    1930         *
    1931         * @see #getNegativeItemLabelPosition(int, int)
    1932         */
    1933        public ItemLabelPosition getPositiveItemLabelPosition(int row, int column) {
    1934            return getSeriesPositiveItemLabelPosition(row);
    1935        }
    1936
    1937        /**
    1938         * Returns the item label position for positive values in ALL series.
    1939         *
    1940         * @return The item label position (possibly <code>null</code>).
    1941         *
    1942         * @see #setPositiveItemLabelPosition(ItemLabelPosition)
    1943         */
    1944        public ItemLabelPosition getPositiveItemLabelPosition() {
    1945            return this.positiveItemLabelPosition;
    1946        }
    1947
    1948        /**
    1949         * Sets the item label position for positive values in ALL series, and
    1950         * sends a {@link RendererChangeEvent} to all registered listeners.  You
    1951         * need to set this to <code>null</code> to expose the settings for
    1952         * individual series.
    1953         *
    1954         * @param position  the position (<code>null</code> permitted).
    1955         *
    1956         * @see #getPositiveItemLabelPosition()
    1957         */
    1958        public void setPositiveItemLabelPosition(ItemLabelPosition position) {
    1959            setPositiveItemLabelPosition(position, true);
    1960        }
    1961
    1962        /**
    1963         * Sets the positive item label position for ALL series and (if requested)
    1964         * sends a {@link RendererChangeEvent} to all registered listeners.
    1965         *
    1966         * @param position  the position (<code>null</code> permitted).
    1967         * @param notify  notify registered listeners?
    1968         *
    1969         * @see #getPositiveItemLabelPosition()
    1970         */
    1971        public void setPositiveItemLabelPosition(ItemLabelPosition position,
    1972                                                 boolean notify) {
    1973            this.positiveItemLabelPosition = position;
    1974            if (notify) {
    1975                fireChangeEvent();
    1976            }
    1977        }
    1978
    1979        /**
    1980         * Returns the item label position for all positive values in a series.
    1981         *
    1982         * @param series  the series index (zero-based).
    1983         *
    1984         * @return The item label position (never <code>null</code>).
    1985         *
    1986         * @see #setSeriesPositiveItemLabelPosition(int, ItemLabelPosition)
    1987         */
    1988        public ItemLabelPosition getSeriesPositiveItemLabelPosition(int series) {
    1989
    1990            // return the override, if there is one...
    1991            if (this.positiveItemLabelPosition != null) {
    1992                return this.positiveItemLabelPosition;
    1993            }
    1994
    1995            // otherwise look up the position table
    1996            ItemLabelPosition position = (ItemLabelPosition)
    1997                this.positiveItemLabelPositionList.get(series);
    1998            if (position == null) {
    1999                position = this.basePositiveItemLabelPosition;
    2000            }
    2001            return position;
    2002
    2003        }
    2004
    2005        /**
    2006         * Sets the item label position for all positive values in a series and
    2007         * sends a {@link RendererChangeEvent} to all registered listeners.
    2008         *
    2009         * @param series  the series index (zero-based).
    2010         * @param position  the position (<code>null</code> permitted).
    2011         *
    2012         * @see #getSeriesPositiveItemLabelPosition(int)
    2013         */
    2014        public void setSeriesPositiveItemLabelPosition(int series,
    2015                                                       ItemLabelPosition position) {
    2016            setSeriesPositiveItemLabelPosition(series, position, true);
    2017        }
    2018
    2019        /**
    2020         * Sets the item label position for all positive values in a series and (if
    2021         * requested) sends a {@link RendererChangeEvent} to all registered
    2022         * listeners.
    2023         *
    2024         * @param series  the series index (zero-based).
    2025         * @param position  the position (<code>null</code> permitted).
    2026         * @param notify  notify registered listeners?
    2027         *
    2028         * @see #getSeriesPositiveItemLabelPosition(int)
    2029         */
    2030        public void setSeriesPositiveItemLabelPosition(int series,
    2031                                                       ItemLabelPosition position,
    2032                                                       boolean notify) {
    2033            this.positiveItemLabelPositionList.set(series, position);
    2034            if (notify) {
    2035                fireChangeEvent();
    2036            }
    2037        }
    2038
    2039        /**
    2040         * Returns the base positive item label position.
    2041         *
    2042         * @return The position (never <code>null</code>).
    2043         *
    2044         * @see #setBasePositiveItemLabelPosition(ItemLabelPosition)
    2045         */
    2046        public ItemLabelPosition getBasePositiveItemLabelPosition() {
    2047            return this.basePositiveItemLabelPosition;
    2048        }
    2049
    2050        /**
    2051         * Sets the base positive item label position.
    2052         *
    2053         * @param position  the position (<code>null</code> not permitted).
    2054         *
    2055         * @see #getBasePositiveItemLabelPosition()
    2056         */
    2057        public void setBasePositiveItemLabelPosition(ItemLabelPosition position) {
    2058            // defer argument checking...
    2059            setBasePositiveItemLabelPosition(position, true);
    2060        }
    2061
    2062        /**
    2063         * Sets the base positive item label position and, if requested, sends a
    2064         * {@link RendererChangeEvent} to all registered listeners.
    2065         *
    2066         * @param position  the position (<code>null</code> not permitted).
    2067         * @param notify  notify registered listeners?
    2068         *
    2069         * @see #getBasePositiveItemLabelPosition()
    2070         */
    2071        public void setBasePositiveItemLabelPosition(ItemLabelPosition position,
    2072                                                     boolean notify) {
    2073            if (position == null) {
    2074                throw new IllegalArgumentException("Null 'position' argument.");
    2075            }
    2076            this.basePositiveItemLabelPosition = position;
    2077            if (notify) {
    2078                fireChangeEvent();
    2079            }
    2080        }
    2081
    2082        // NEGATIVE ITEM LABEL POSITION...
    2083
    2084        /**
    2085         * Returns the item label position for negative values.  This method can be
    2086         * overridden to provide customisation of the item label position for
    2087         * individual data items.
    2088         *
    2089         * @param row  the row index (zero-based).
    2090         * @param column  the column (zero-based).
    2091         *
    2092         * @return The item label position (never <code>null</code>).
    2093         *
    2094         * @see #getPositiveItemLabelPosition(int, int)
    2095         */
    2096        public ItemLabelPosition getNegativeItemLabelPosition(int row, int column) {
    2097            return getSeriesNegativeItemLabelPosition(row);
    2098        }
    2099
    2100        /**
    2101         * Returns the item label position for negative values in ALL series.
    2102         *
    2103         * @return The item label position (possibly <code>null</code>).
    2104         *
    2105         * @see #setNegativeItemLabelPosition(ItemLabelPosition)
    2106         */
    2107        public ItemLabelPosition getNegativeItemLabelPosition() {
    2108            return this.negativeItemLabelPosition;
    2109        }
    2110
    2111        /**
    2112         * Sets the item label position for negative values in ALL series, and
    2113         * sends a {@link RendererChangeEvent} to all registered listeners.  You
    2114         * need to set this to <code>null</code> to expose the settings for
    2115         * individual series.
    2116         *
    2117         * @param position  the position (<code>null</code> permitted).
    2118         *
    2119         * @see #getNegativeItemLabelPosition()
    2120         */
    2121        public void setNegativeItemLabelPosition(ItemLabelPosition position) {
    2122            setNegativeItemLabelPosition(position, true);
    2123        }
    2124
    2125        /**
    2126         * Sets the item label position for negative values in ALL series and (if
    2127         * requested) sends a {@link RendererChangeEvent} to all registered
    2128         * listeners.
    2129         *
    2130         * @param position  the position (<code>null</code> permitted).
    2131         * @param notify  notify registered listeners?
    2132         *
    2133         * @see #getNegativeItemLabelPosition()
    2134         */
    2135        public void setNegativeItemLabelPosition(ItemLabelPosition position,
    2136                                                 boolean notify) {
    2137            this.negativeItemLabelPosition = position;
    2138            if (notify) {
    2139                fireChangeEvent();
    2140            }
    2141        }
    2142
    2143        /**
    2144         * Returns the item label position for all negative values in a series.
    2145         *
    2146         * @param series  the series index (zero-based).
    2147         *
    2148         * @return The item label position (never <code>null</code>).
    2149         *
    2150         * @see #setSeriesNegativeItemLabelPosition(int, ItemLabelPosition)
    2151         */
    2152        public ItemLabelPosition getSeriesNegativeItemLabelPosition(int series) {
    2153
    2154            // return the override, if there is one...
    2155            if (this.negativeItemLabelPosition != null) {
    2156                return this.negativeItemLabelPosition;
    2157            }
    2158
    2159            // otherwise look up the position list
    2160            ItemLabelPosition position = (ItemLabelPosition)
    2161                this.negativeItemLabelPositionList.get(series);
    2162            if (position == null) {
    2163                position = this.baseNegativeItemLabelPosition;
    2164            }
    2165            return position;
    2166
    2167        }
    2168
    2169        /**
    2170         * Sets the item label position for negative values in a series and sends a
    2171         * {@link RendererChangeEvent} to all registered listeners.
    2172         *
    2173         * @param series  the series index (zero-based).
    2174         * @param position  the position (<code>null</code> permitted).
    2175         *
    2176         * @see #getSeriesNegativeItemLabelPosition(int)
    2177         */
    2178        public void setSeriesNegativeItemLabelPosition(int series,
    2179                                                       ItemLabelPosition position) {
    2180            setSeriesNegativeItemLabelPosition(series, position, true);
    2181        }
    2182
    2183        /**
    2184         * Sets the item label position for negative values in a series and (if
    2185         * requested) sends a {@link RendererChangeEvent} to all registered
    2186         * listeners.
    2187         *
    2188         * @param series  the series index (zero-based).
    2189         * @param position  the position (<code>null</code> permitted).
    2190         * @param notify  notify registered listeners?
    2191         *
    2192         * @see #getSeriesNegativeItemLabelPosition(int)
    2193         */
    2194        public void setSeriesNegativeItemLabelPosition(int series,
    2195                                                       ItemLabelPosition position,
    2196                                                       boolean notify) {
    2197            this.negativeItemLabelPositionList.set(series, position);
    2198            if (notify) {
    2199                fireChangeEvent();
    2200            }
    2201        }
    2202
    2203        /**
    2204         * Returns the base item label position for negative values.
    2205         *
    2206         * @return The position (never <code>null</code>).
    2207         *
    2208         * @see #setBaseNegativeItemLabelPosition(ItemLabelPosition)
    2209         */
    2210        public ItemLabelPosition getBaseNegativeItemLabelPosition() {
    2211            return this.baseNegativeItemLabelPosition;
    2212        }
    2213
    2214        /**
    2215         * Sets the base item label position for negative values and sends a
    2216         * {@link RendererChangeEvent} to all registered listeners.
    2217         *
    2218         * @param position  the position (<code>null</code> not permitted).
    2219         *
    2220         * @see #getBaseNegativeItemLabelPosition()
    2221         */
    2222        public void setBaseNegativeItemLabelPosition(ItemLabelPosition position) {
    2223            setBaseNegativeItemLabelPosition(position, true);
    2224        }
    2225
    2226        /**
    2227         * Sets the base negative item label position and, if requested, sends a
    2228         * {@link RendererChangeEvent} to all registered listeners.
    2229         *
    2230         * @param position  the position (<code>null</code> not permitted).
    2231         * @param notify  notify registered listeners?
    2232         *
    2233         * @see #getBaseNegativeItemLabelPosition()
    2234         */
    2235        public void setBaseNegativeItemLabelPosition(ItemLabelPosition position,
    2236                                                     boolean notify) {
    2237            if (position == null) {
    2238                throw new IllegalArgumentException("Null 'position' argument.");
    2239            }
    2240            this.baseNegativeItemLabelPosition = position;
    2241            if (notify) {
    2242                fireChangeEvent();
    2243            }
    2244        }
    2245
    2246        /**
    2247         * Returns the item label anchor offset.
    2248         *
    2249         * @return The offset.
    2250         *
    2251         * @see #setItemLabelAnchorOffset(double)
    2252         */
    2253        public double getItemLabelAnchorOffset() {
    2254            return this.itemLabelAnchorOffset;
    2255        }
    2256
    2257        /**
    2258         * Sets the item label anchor offset.
    2259         *
    2260         * @param offset  the offset.
    2261         *
    2262         * @see #getItemLabelAnchorOffset()
    2263         */
    2264        public void setItemLabelAnchorOffset(double offset) {
    2265            this.itemLabelAnchorOffset = offset;
    2266            fireChangeEvent();
    2267        }
    2268
    2269        /**
    2270         * Returns a boolean that indicates whether or not the specified item
    2271         * should have a chart entity created for it.
    2272         *
    2273         * @param series  the series index.
    2274         * @param item  the item index.
    2275         *
    2276         * @return A boolean.
    2277         */
    2278        public boolean getItemCreateEntity(int series, int item) {
    2279            if (this.createEntities != null) {
    2280                return this.createEntities.booleanValue();
    2281            }
    2282            else {
    2283                Boolean b = getSeriesCreateEntities(series);
    2284                if (b != null) {
    2285                    return b.booleanValue();
    2286                }
    2287                else {
    2288                    return this.baseCreateEntities;
    2289                }
    2290            }
    2291        }
    2292
    2293        /**
    2294         * Returns the flag that controls whether or not chart entities are created
    2295         * for the items in ALL series.  This flag overrides the per series and
    2296         * default settings - you must set it to <code>null</code> if you want the
    2297         * other settings to apply.
    2298         *
    2299         * @return The flag (possibly <code>null</code>).
    2300         */
    2301        public Boolean getCreateEntities() {
    2302            return this.createEntities;
    2303        }
    2304
    2305        /**
    2306         * Sets the flag that controls whether or not chart entities are created
    2307         * for the items in ALL series, and sends a {@link RendererChangeEvent} to
    2308         * all registered listeners.  This flag overrides the per series and
    2309         * default settings - you must set it to <code>null</code> if you want the
    2310         * other settings to apply.
    2311         *
    2312         * @param create  the flag (<code>null</code> permitted).
    2313         */
    2314        public void setCreateEntities(Boolean create) {
    2315             setCreateEntities(create, true);
    2316        }
    2317
    2318        /**
    2319         * Sets the flag that controls whether or not chart entities are created
    2320         * for the items in ALL series, and sends a {@link RendererChangeEvent} to
    2321         * all registered listeners.  This flag overrides the per series and
    2322         * default settings - you must set it to <code>null</code> if you want the
    2323         * other settings to apply.
    2324         *
    2325         * @param create  the flag (<code>null</code> permitted).
    2326         * @param notify  notify listeners?
    2327         */
    2328        public void setCreateEntities(Boolean create, boolean notify) {
    2329            this.createEntities = create;
    2330            if (notify) {
    2331                fireChangeEvent();
    2332            }
    2333        }
    2334
    2335        /**
    2336         * Returns the flag that controls whether entities are created for a
    2337         * series.
    2338         *
    2339         * @param series  the series index (zero-based).
    2340         *
    2341         * @return The flag (possibly <code>null</code>).
    2342         */
    2343        public Boolean getSeriesCreateEntities(int series) {
    2344            return this.createEntitiesList.getBoolean(series);
    2345        }
    2346
    2347        /**
    2348         * Sets the flag that controls whether entities are created for a series,
    2349         * and sends a {@link RendererChangeEvent} to all registered listeners.
    2350         *
    2351         * @param series  the series index (zero-based).
    2352         * @param create  the flag (<code>null</code> permitted).
    2353         */
    2354        public void setSeriesCreateEntities(int series, Boolean create) {
    2355            setSeriesCreateEntities(series, create, true);
    2356        }
    2357
    2358        /**
    2359         * Sets the flag that controls whether entities are created for a series
    2360         * and, if requested, sends a {@link RendererChangeEvent} to all registered
    2361         * listeners.
    2362         *
    2363         * @param series  the series index.
    2364         * @param create  the flag (<code>null</code> permitted).
    2365         * @param notify  notify listeners?
    2366         */
    2367        public void setSeriesCreateEntities(int series, Boolean create,
    2368                                            boolean notify) {
    2369            this.createEntitiesList.setBoolean(series, create);
    2370            if (notify) {
    2371                fireChangeEvent();
    2372            }
    2373        }
    2374
    2375        /**
    2376         * Returns the base visibility for all series.
    2377         *
    2378         * @return The base visibility.
    2379         */
    2380        public boolean getBaseCreateEntities() {
    2381            return this.baseCreateEntities;
    2382        }
    2383
    2384        /**
    2385         * Sets the base flag that controls whether entities are created
    2386         * for a series, and sends a {@link RendererChangeEvent}
    2387         * to all registered listeners.
    2388         *
    2389         * @param create  the flag.
    2390         */
    2391        public void setBaseCreateEntities(boolean create) {
    2392            // defer argument checking...
    2393            setBaseCreateEntities(create, true);
    2394        }
    2395
    2396        /**
    2397         * Sets the base flag that controls whether entities are created and,
    2398         * if requested, sends a {@link RendererChangeEvent} to all registered
    2399         * listeners.
    2400         *
    2401         * @param create  the visibility.
    2402         * @param notify  notify listeners?
    2403         */
    2404        public void setBaseCreateEntities(boolean create, boolean notify) {
    2405            this.baseCreateEntities = create;
    2406            if (notify) {
    2407                fireChangeEvent();
    2408            }
    2409        }
    2410
    2411        /** The adjacent offset. */
    2412        private static final double ADJ = Math.cos(Math.PI / 6.0);
    2413
    2414        /** The opposite offset. */
    2415        private static final double OPP = Math.sin(Math.PI / 6.0);
    2416
    2417        /**
    2418         * Calculates the item label anchor point.
    2419         *
    2420         * @param anchor  the anchor.
    2421         * @param x  the x coordinate.
    2422         * @param y  the y coordinate.
    2423         * @param orientation  the plot orientation.
    2424         *
    2425         * @return The anchor point (never <code>null</code>).
    2426         */
    2427        protected Point2D calculateLabelAnchorPoint(ItemLabelAnchor anchor,
    2428                double x, double y, PlotOrientation orientation) {
    2429            Point2D result = null;
    2430            if (anchor == ItemLabelAnchor.CENTER) {
    2431                result = new Point2D.Double(x, y);
    2432            }
    2433            else if (anchor == ItemLabelAnchor.INSIDE1) {
    2434                result = new Point2D.Double(x + OPP * this.itemLabelAnchorOffset,
    2435                        y - ADJ * this.itemLabelAnchorOffset);
    2436            }
    2437            else if (anchor == ItemLabelAnchor.INSIDE2) {
    2438                result = new Point2D.Double(x + ADJ * this.itemLabelAnchorOffset,
    2439                        y - OPP * this.itemLabelAnchorOffset);
    2440            }
    2441            else if (anchor == ItemLabelAnchor.INSIDE3) {
    2442                result = new Point2D.Double(x + this.itemLabelAnchorOffset, y);
    2443            }
    2444            else if (anchor == ItemLabelAnchor.INSIDE4) {
    2445                result = new Point2D.Double(x + ADJ * this.itemLabelAnchorOffset,
    2446                        y + OPP * this.itemLabelAnchorOffset);
    2447            }
    2448            else if (anchor == ItemLabelAnchor.INSIDE5) {
    2449                result = new Point2D.Double(x + OPP * this.itemLabelAnchorOffset,
    2450                        y + ADJ * this.itemLabelAnchorOffset);
    2451            }
    2452            else if (anchor == ItemLabelAnchor.INSIDE6) {
    2453                result = new Point2D.Double(x, y + this.itemLabelAnchorOffset);
    2454            }
    2455            else if (anchor == ItemLabelAnchor.INSIDE7) {
    2456                result = new Point2D.Double(x - OPP * this.itemLabelAnchorOffset,
    2457                        y + ADJ * this.itemLabelAnchorOffset);
    2458            }
    2459            else if (anchor == ItemLabelAnchor.INSIDE8) {
    2460                result = new Point2D.Double(x - ADJ * this.itemLabelAnchorOffset,
    2461                        y + OPP * this.itemLabelAnchorOffset);
    2462            }
    2463            else if (anchor == ItemLabelAnchor.INSIDE9) {
    2464                result = new Point2D.Double(x - this.itemLabelAnchorOffset, y);
    2465            }
    2466            else if (anchor == ItemLabelAnchor.INSIDE10) {
    2467                result = new Point2D.Double(x - ADJ * this.itemLabelAnchorOffset,
    2468                        y - OPP * this.itemLabelAnchorOffset);
    2469            }
    2470            else if (anchor == ItemLabelAnchor.INSIDE11) {
    2471                result = new Point2D.Double(x - OPP * this.itemLabelAnchorOffset,
    2472                        y - ADJ * this.itemLabelAnchorOffset);
    2473            }
    2474            else if (anchor == ItemLabelAnchor.INSIDE12) {
    2475                result = new Point2D.Double(x, y - this.itemLabelAnchorOffset);
    2476            }
    2477            else if (anchor == ItemLabelAnchor.OUTSIDE1) {
    2478                result = new Point2D.Double(
    2479                        x + 2.0 * OPP * this.itemLabelAnchorOffset,
    2480                        y - 2.0 * ADJ * this.itemLabelAnchorOffset);
    2481            }
    2482            else if (anchor == ItemLabelAnchor.OUTSIDE2) {
    2483                result = new Point2D.Double(
    2484                        x + 2.0 * ADJ * this.itemLabelAnchorOffset,
    2485                        y - 2.0 * OPP * this.itemLabelAnchorOffset);
    2486            }
    2487            else if (anchor == ItemLabelAnchor.OUTSIDE3) {
    2488                result = new Point2D.Double(x + 2.0 * this.itemLabelAnchorOffset,
    2489                        y);
    2490            }
    2491            else if (anchor == ItemLabelAnchor.OUTSIDE4) {
    2492                result = new Point2D.Double(
    2493                        x + 2.0 * ADJ * this.itemLabelAnchorOffset,
    2494                        y + 2.0 * OPP * this.itemLabelAnchorOffset);
    2495            }
    2496            else if (anchor == ItemLabelAnchor.OUTSIDE5) {
    2497                result = new Point2D.Double(
    2498                        x + 2.0 * OPP * this.itemLabelAnchorOffset,
    2499                        y + 2.0 * ADJ * this.itemLabelAnchorOffset);
    2500            }
    2501            else if (anchor == ItemLabelAnchor.OUTSIDE6) {
    2502                result = new Point2D.Double(x,
    2503                        y + 2.0 * this.itemLabelAnchorOffset);
    2504            }
    2505            else if (anchor == ItemLabelAnchor.OUTSIDE7) {
    2506                result = new Point2D.Double(
    2507                        x - 2.0 * OPP * this.itemLabelAnchorOffset,
    2508                        y + 2.0 * ADJ * this.itemLabelAnchorOffset);
    2509            }
    2510            else if (anchor == ItemLabelAnchor.OUTSIDE8) {
    2511                result = new Point2D.Double(
    2512                        x - 2.0 * ADJ * this.itemLabelAnchorOffset,
    2513                        y + 2.0 * OPP * this.itemLabelAnchorOffset);
    2514            }
    2515            else if (anchor == ItemLabelAnchor.OUTSIDE9) {
    2516                result = new Point2D.Double(x - 2.0 * this.itemLabelAnchorOffset,
    2517                        y);
    2518            }
    2519            else if (anchor == ItemLabelAnchor.OUTSIDE10) {
    2520                result = new Point2D.Double(
    2521                        x - 2.0 * ADJ * this.itemLabelAnchorOffset,
    2522                        y - 2.0 * OPP * this.itemLabelAnchorOffset);
    2523            }
    2524            else if (anchor == ItemLabelAnchor.OUTSIDE11) {
    2525                result = new Point2D.Double(
    2526                    x - 2.0 * OPP * this.itemLabelAnchorOffset,
    2527                    y - 2.0 * ADJ * this.itemLabelAnchorOffset);
    2528            }
    2529            else if (anchor == ItemLabelAnchor.OUTSIDE12) {
    2530                result = new Point2D.Double(x,
    2531                        y - 2.0 * this.itemLabelAnchorOffset);
    2532            }
    2533            return result;
    2534        }
    2535
    2536        /**
    2537         * Registers an object to receive notification of changes to the renderer.
    2538         *
    2539         * @param listener  the listener (<code>null</code> not permitted).
    2540         */
    2541        public void addChangeListener(RendererChangeListener listener) {
    2542            if (listener == null) {
    2543                throw new IllegalArgumentException("Null 'listener' argument.");
    2544            }
    2545            this.listenerList.add(RendererChangeListener.class, listener);
    2546        }
    2547
    2548        /**
    2549         * Deregisters an object so that it no longer receives
    2550         * notification of changes to the renderer.
    2551         *
    2552         * @param listener  the object (<code>null</code> not permitted).
    2553         */
    2554        public void removeChangeListener(RendererChangeListener listener) {
    2555            if (listener == null) {
    2556                throw new IllegalArgumentException("Null 'listener' argument.");
    2557            }
    2558            this.listenerList.remove(RendererChangeListener.class, listener);
    2559        }
    2560
    2561        /**
    2562         * Returns <code>true</code> if the specified object is registered with
    2563         * the dataset as a listener.  Most applications won't need to call this
    2564         * method, it exists mainly for use by unit testing code.
    2565         *
    2566         * @param listener  the listener.
    2567         *
    2568         * @return A boolean.
    2569         */
    2570        public boolean hasListener(EventListener listener) {
    2571            List list = Arrays.asList(this.listenerList.getListenerList());
    2572            return list.contains(listener);
    2573        }
    2574
    2575        /**
    2576         * Sends a {@link RendererChangeEvent} to all registered listeners.
    2577         *
    2578         * @since 1.0.5
    2579         */
    2580        protected void fireChangeEvent() {
    2581
    2582            // the commented out code would be better, but only if
    2583            // RendererChangeEvent is immutable, which it isn't.  See if there is
    2584            // a way to fix this...
    2585
    2586            //if (this.event == null) {
    2587            //    this.event = new RendererChangeEvent(this);
    2588            //}
    2589            //notifyListeners(this.event);
    2590
    2591            notifyListeners(new RendererChangeEvent(this));
    2592        }
    2593
    2594        /**
    2595         * Notifies all registered listeners that the renderer has been modified.
    2596         *
    2597         * @param event  information about the change event.
    2598         */
    2599        public void notifyListeners(RendererChangeEvent event) {
    2600            Object[] ls = this.listenerList.getListenerList();
    2601            for (int i = ls.length - 2; i >= 0; i -= 2) {
    2602                if (ls[i] == RendererChangeListener.class) {
    2603                    ((RendererChangeListener) ls[i + 1]).rendererChanged(event);
    2604                }
    2605            }
    2606        }
    2607
    2608        /**
    2609         * Tests this renderer for equality with another object.
    2610         *
    2611         * @param obj  the object (<code>null</code> permitted).
    2612         *
    2613         * @return <code>true</code> or <code>false</code>.
    2614         */
    2615        public boolean equals(Object obj) {
    2616            if (obj == this) {
    2617                return true;
    2618            }
    2619            if (!(obj instanceof AbstractRenderer)) {
    2620                return false;
    2621            }
    2622            AbstractRenderer that = (AbstractRenderer) obj;
    2623            if (!ObjectUtilities.equal(this.seriesVisible, that.seriesVisible)) {
    2624                return false;
    2625            }
    2626            if (!this.seriesVisibleList.equals(that.seriesVisibleList)) {
    2627                return false;
    2628            }
    2629            if (this.baseSeriesVisible != that.baseSeriesVisible) {
    2630                return false;
    2631            }
    2632            if (!ObjectUtilities.equal(this.seriesVisibleInLegend,
    2633                    that.seriesVisibleInLegend)) {
    2634                return false;
    2635            }
    2636            if (!this.seriesVisibleInLegendList.equals(
    2637                    that.seriesVisibleInLegendList)) {
    2638                return false;
    2639            }
    2640            if (this.baseSeriesVisibleInLegend != that.baseSeriesVisibleInLegend) {
    2641                return false;
    2642            }
    2643            if (!PaintUtilities.equal(this.paint, that.paint)) {
    2644                return false;
    2645            }
    2646            if (!ObjectUtilities.equal(this.paintList, that.paintList)) {
    2647                return false;
    2648            }
    2649            if (!PaintUtilities.equal(this.basePaint, that.basePaint)) {
    2650                return false;
    2651            }
    2652            if (!PaintUtilities.equal(this.fillPaint, that.fillPaint)) {
    2653                return false;
    2654            }
    2655            if (!ObjectUtilities.equal(this.fillPaintList, that.fillPaintList)) {
    2656                return false;
    2657            }
    2658            if (!PaintUtilities.equal(this.baseFillPaint, that.baseFillPaint)) {
    2659                return false;
    2660            }
    2661            if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) {
    2662                return false;
    2663            }
    2664            if (!ObjectUtilities.equal(this.outlinePaintList,
    2665                    that.outlinePaintList)) {
    2666                return false;
    2667            }
    2668            if (!PaintUtilities.equal(this.baseOutlinePaint,
    2669                    that.baseOutlinePaint)) {
    2670                return false;
    2671            }
    2672            if (!ObjectUtilities.equal(this.stroke, that.stroke)) {
    2673                return false;
    2674            }
    2675            if (!ObjectUtilities.equal(this.strokeList, that.strokeList)) {
    2676                return false;
    2677            }
    2678            if (!ObjectUtilities.equal(this.baseStroke, that.baseStroke)) {
    2679                return false;
    2680            }
    2681            if (!ObjectUtilities.equal(this.outlineStroke, that.outlineStroke)) {
    2682                return false;
    2683            }
    2684            if (!ObjectUtilities.equal(this.outlineStrokeList,
    2685                    that.outlineStrokeList)) {
    2686                return false;
    2687            }
    2688            if (!ObjectUtilities.equal(
    2689                this.baseOutlineStroke, that.baseOutlineStroke)
    2690            ) {
    2691                return false;
    2692            }
    2693            if (!ObjectUtilities.equal(this.shape, that.shape)) {
    2694                return false;
    2695            }
    2696            if (!ObjectUtilities.equal(this.shapeList, that.shapeList)) {
    2697                return false;
    2698            }
    2699            if (!ObjectUtilities.equal(this.baseShape, that.baseShape)) {
    2700                return false;
    2701            }
    2702            if (!ObjectUtilities.equal(this.itemLabelsVisible,
    2703                    that.itemLabelsVisible)) {
    2704                return false;
    2705            }
    2706            if (!ObjectUtilities.equal(this.itemLabelsVisibleList,
    2707                    that.itemLabelsVisibleList)) {
    2708                return false;
    2709            }
    2710            if (!ObjectUtilities.equal(this.baseItemLabelsVisible,
    2711                    that.baseItemLabelsVisible)) {
    2712                return false;
    2713            }
    2714            if (!ObjectUtilities.equal(this.itemLabelFont, that.itemLabelFont)) {
    2715                return false;
    2716            }
    2717            if (!ObjectUtilities.equal(this.itemLabelFontList,
    2718                    that.itemLabelFontList)) {
    2719                return false;
    2720            }
    2721            if (!ObjectUtilities.equal(this.baseItemLabelFont,
    2722                    that.baseItemLabelFont)) {
    2723                return false;
    2724            }
    2725
    2726            if (!PaintUtilities.equal(this.itemLabelPaint, that.itemLabelPaint)) {
    2727                return false;
    2728            }
    2729            if (!ObjectUtilities.equal(this.itemLabelPaintList,
    2730                    that.itemLabelPaintList)) {
    2731                return false;
    2732            }
    2733            if (!PaintUtilities.equal(this.baseItemLabelPaint,
    2734                    that.baseItemLabelPaint)) {
    2735                return false;
    2736            }
    2737
    2738            if (!ObjectUtilities.equal(this.positiveItemLabelPosition,
    2739                    that.positiveItemLabelPosition)) {
    2740                return false;
    2741            }
    2742            if (!ObjectUtilities.equal(this.positiveItemLabelPositionList,
    2743                    that.positiveItemLabelPositionList)) {
    2744                return false;
    2745            }
    2746            if (!ObjectUtilities.equal(this.basePositiveItemLabelPosition,
    2747                    that.basePositiveItemLabelPosition)) {
    2748                return false;
    2749            }
    2750
    2751            if (!ObjectUtilities.equal(this.negativeItemLabelPosition,
    2752                    that.negativeItemLabelPosition)) {
    2753                return false;
    2754            }
    2755            if (!ObjectUtilities.equal(this.negativeItemLabelPositionList,
    2756                    that.negativeItemLabelPositionList)) {
    2757                return false;
    2758            }
    2759            if (!ObjectUtilities.equal(this.baseNegativeItemLabelPosition,
    2760                    that.baseNegativeItemLabelPosition)) {
    2761                return false;
    2762            }
    2763            if (this.itemLabelAnchorOffset != that.itemLabelAnchorOffset) {
    2764                return false;
    2765            }
    2766            if (!ObjectUtilities.equal(this.createEntities, that.createEntities)) {
    2767                return false;
    2768            }
    2769            if (!ObjectUtilities.equal(this.createEntitiesList,
    2770                    that.createEntitiesList)) {
    2771                return false;
    2772            }
    2773            if (this.baseCreateEntities != that.baseCreateEntities) {
    2774                return false;
    2775            }
    2776            return true;
    2777        }
    2778
    2779        /**
    2780         * Returns a hashcode for the renderer.
    2781         *
    2782         * @return The hashcode.
    2783         */
    2784        public int hashCode() {
    2785            int result = 193;
    2786            result = 37 * result + ObjectUtilities.hashCode(this.stroke);
    2787            result = 37 * result + ObjectUtilities.hashCode(this.baseStroke);
    2788            result = 37 * result + ObjectUtilities.hashCode(this.outlineStroke);
    2789            result = 37 * result + ObjectUtilities.hashCode(this.baseOutlineStroke);
    2790            return result;
    2791        }
    2792
    2793        /**
    2794         * Returns an independent copy of the renderer.
    2795         *
    2796         * @return A clone.
    2797         *
    2798         * @throws CloneNotSupportedException if some component of the renderer
    2799         *         does not support cloning.
    2800         */
    2801        protected Object clone() throws CloneNotSupportedException {
    2802            AbstractRenderer clone = (AbstractRenderer) super.clone();
    2803
    2804            if (this.seriesVisibleList != null) {
    2805                clone.seriesVisibleList
    2806                        = (BooleanList) this.seriesVisibleList.clone();
    2807            }
    2808
    2809            if (this.seriesVisibleInLegendList != null) {
    2810                clone.seriesVisibleInLegendList
    2811                        = (BooleanList) this.seriesVisibleInLegendList.clone();
    2812            }
    2813
    2814            // 'paint' : immutable, no need to clone reference
    2815            if (this.paintList != null) {
    2816                clone.paintList = (PaintList) this.paintList.clone();
    2817            }
    2818            // 'basePaint' : immutable, no need to clone reference
    2819
    2820            if (this.fillPaintList != null) {
    2821                clone.fillPaintList = (PaintList) this.fillPaintList.clone();
    2822            }
    2823            // 'outlinePaint' : immutable, no need to clone reference
    2824            if (this.outlinePaintList != null) {
    2825                clone.outlinePaintList = (PaintList) this.outlinePaintList.clone();
    2826            }
    2827            // 'baseOutlinePaint' : immutable, no need to clone reference
    2828
    2829            // 'stroke' : immutable, no need to clone reference
    2830            if (this.strokeList != null) {
    2831                clone.strokeList = (StrokeList) this.strokeList.clone();
    2832            }
    2833            // 'baseStroke' : immutable, no need to clone reference
    2834
    2835            // 'outlineStroke' : immutable, no need to clone reference
    2836            if (this.outlineStrokeList != null) {
    2837                clone.outlineStrokeList
    2838                    = (StrokeList) this.outlineStrokeList.clone();
    2839            }
    2840            // 'baseOutlineStroke' : immutable, no need to clone reference
    2841
    2842            if (this.shape != null) {
    2843                clone.shape = ShapeUtilities.clone(this.shape);
    2844            }
    2845            if (this.shapeList != null) {
    2846                clone.shapeList = (ShapeList) this.shapeList.clone();
    2847            }
    2848            if (this.baseShape != null) {
    2849                clone.baseShape = ShapeUtilities.clone(this.baseShape);
    2850            }
    2851
    2852            // 'itemLabelsVisible' : immutable, no need to clone reference
    2853            if (this.itemLabelsVisibleList != null) {
    2854                clone.itemLabelsVisibleList
    2855                    = (BooleanList) this.itemLabelsVisibleList.clone();
    2856            }
    2857            // 'basePaint' : immutable, no need to clone reference
    2858
    2859            // 'itemLabelFont' : immutable, no need to clone reference
    2860            if (this.itemLabelFontList != null) {
    2861                clone.itemLabelFontList
    2862                    = (ObjectList) this.itemLabelFontList.clone();
    2863            }
    2864            // 'baseItemLabelFont' : immutable, no need to clone reference
    2865
    2866            // 'itemLabelPaint' : immutable, no need to clone reference
    2867            if (this.itemLabelPaintList != null) {
    2868                clone.itemLabelPaintList
    2869                    = (PaintList) this.itemLabelPaintList.clone();
    2870            }
    2871            // 'baseItemLabelPaint' : immutable, no need to clone reference
    2872
    2873            // 'postiveItemLabelAnchor' : immutable, no need to clone reference
    2874            if (this.positiveItemLabelPositionList != null) {
    2875                clone.positiveItemLabelPositionList
    2876                    = (ObjectList) this.positiveItemLabelPositionList.clone();
    2877            }
    2878            // 'baseItemLabelAnchor' : immutable, no need to clone reference
    2879
    2880            // 'negativeItemLabelAnchor' : immutable, no need to clone reference
    2881            if (this.negativeItemLabelPositionList != null) {
    2882                clone.negativeItemLabelPositionList
    2883                    = (ObjectList) this.negativeItemLabelPositionList.clone();
    2884            }
    2885            // 'baseNegativeItemLabelAnchor' : immutable, no need to clone reference
    2886
    2887            if (this.createEntitiesList != null) {
    2888                clone.createEntitiesList
    2889                        = (BooleanList) this.createEntitiesList.clone();
    2890            }
    2891            clone.listenerList = new EventListenerList();
    2892            clone.event = null;
    2893            return clone;
    2894        }
    2895
    2896        /**
    2897         * Provides serialization support.
    2898         *
    2899         * @param stream  the output stream.
    2900         *
    2901         * @throws IOException  if there is an I/O error.
    2902         */
    2903        private void writeObject(ObjectOutputStream stream) throws IOException {
    2904
    2905            stream.defaultWriteObject();
    2906            SerialUtilities.writePaint(this.paint, stream);
    2907            SerialUtilities.writePaint(this.basePaint, stream);
    2908            SerialUtilities.writePaint(this.fillPaint, stream);
    2909            SerialUtilities.writePaint(this.baseFillPaint, stream);
    2910            SerialUtilities.writePaint(this.outlinePaint, stream);
    2911            SerialUtilities.writePaint(this.baseOutlinePaint, stream);
    2912            SerialUtilities.writeStroke(this.stroke, stream);
    2913            SerialUtilities.writeStroke(this.baseStroke, stream);
    2914            SerialUtilities.writeStroke(this.outlineStroke, stream);
    2915            SerialUtilities.writeStroke(this.baseOutlineStroke, stream);
    2916            SerialUtilities.writeShape(this.shape, stream);
    2917            SerialUtilities.writeShape(this.baseShape, stream);
    2918            SerialUtilities.writePaint(this.itemLabelPaint, stream);
    2919            SerialUtilities.writePaint(this.baseItemLabelPaint, stream);
    2920
    2921        }
    2922
    2923        /**
    2924         * Provides serialization support.
    2925         *
    2926         * @param stream  the input stream.
    2927         *
    2928         * @throws IOException  if there is an I/O error.
    2929         * @throws ClassNotFoundException  if there is a classpath problem.
    2930         */
    2931        private void readObject(ObjectInputStream stream)
    2932            throws IOException, ClassNotFoundException {
    2933
    2934            stream.defaultReadObject();
    2935            this.paint = SerialUtilities.readPaint(stream);
    2936            this.basePaint = SerialUtilities.readPaint(stream);
    2937            this.fillPaint = SerialUtilities.readPaint(stream);
    2938            this.baseFillPaint = SerialUtilities.readPaint(stream);
    2939            this.outlinePaint = SerialUtilities.readPaint(stream);
    2940            this.baseOutlinePaint = SerialUtilities.readPaint(stream);
    2941            this.stroke = SerialUtilities.readStroke(stream);
    2942            this.baseStroke = SerialUtilities.readStroke(stream);
    2943            this.outlineStroke = SerialUtilities.readStroke(stream);
    2944            this.baseOutlineStroke = SerialUtilities.readStroke(stream);
    2945            this.shape = SerialUtilities.readShape(stream);
    2946            this.baseShape = SerialUtilities.readShape(stream);
    2947            this.itemLabelPaint = SerialUtilities.readPaint(stream);
    2948            this.baseItemLabelPaint = SerialUtilities.readPaint(stream);
    2949
    2950            // listeners are not restored automatically, but storage must be
    2951            // provided...
    2952            this.listenerList = new EventListenerList();
    2953
    2954        }
    2955
    2956    }