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