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