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