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