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