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