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