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