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