content: /* ===========================================================
   * JFreeChart : a free chart library for the Java(tm) platform
   * ===========================================================
   *
   * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors.
   *
   * Project Info:  http://www.jfree.org/jfreechart/index.html
   *
   * This library is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation; either version 2.1 of the License, or
   * (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
   * License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
   * USA.
   *
   * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   * Other names may be trademarks of their respective owners.]
   *
   * ---------------------
   * AbstractRenderer.java
   * ---------------------
   * (C) Copyright 2002-2013, by Object Refinery Limited.
   *
   * Original Author:  David Gilbert (for Object Refinery Limited);
   * Contributor(s):   Nicolas Brodu;
   *                   Michael Zinsmaier;
   *
   * Changes:
   * --------
   * 22-Aug-2002 : Version 1, draws code out of AbstractXYItemRenderer to share
   *               with AbstractCategoryItemRenderer (DG);
   * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
   * 06-Nov-2002 : Moved to the com.jrefinery.chart.renderer package (DG);
   * 21-Nov-2002 : Added a paint table for the renderer to use (DG);
   * 17-Jan-2003 : Moved plot classes into a separate package (DG);
   * 25-Mar-2003 : Implemented Serializable (DG);
   * 29-Apr-2003 : Added valueLabelFont and valueLabelPaint attributes, based on
   *               code from Arnaud Lelievre (DG);
   * 29-Jul-2003 : Amended code that doesn't compile with JDK 1.2.2 (DG);
   * 13-Aug-2003 : Implemented Cloneable (DG);
   * 15-Sep-2003 : Fixed serialization (NB);
   * 17-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
   * 07-Oct-2003 : Moved PlotRenderingInfo into RendererState to allow for
   *               multiple threads using a single renderer (DG);
   * 20-Oct-2003 : Added missing setOutlinePaint() method (DG);
   * 23-Oct-2003 : Split item label attributes into 'positive' and 'negative'
   *               values (DG);
   * 26-Nov-2003 : Added methods to get the positive and negative item label
   *               positions (DG);
   * 01-Mar-2004 : Modified readObject() method to prevent null pointer exceptions
   *               after deserialization (DG);
   * 19-Jul-2004 : Fixed bug in getItemLabelFont(int, int) method (DG);
   * 04-Oct-2004 : Updated equals() method, eliminated use of NumberUtils,
   *               renamed BooleanUtils --> BooleanUtilities, ShapeUtils -->
   *               ShapeUtilities (DG);
   * 15-Mar-2005 : Fixed serialization of baseFillPaint (DG);
   * 16-May-2005 : Base outline stroke should never be null (DG);
   * 01-Jun-2005 : Added hasListener() method for unit testing (DG);
   * 08-Jun-2005 : Fixed equals() method to handle GradientPaint (DG);
   * ------------- JFREECHART 1.0.x ---------------------------------------------
   * 02-Feb-2007 : Minor API doc update (DG);
   * 19-Feb-2007 : Fixes for clone() method (DG);
   * 28-Feb-2007 : Use cached event to signal changes (DG);
   * 19-Apr-2007 : Deprecated seriesVisible and seriesVisibleInLegend flags (DG);
   * 20-Apr-2007 : Deprecated paint, fillPaint, outlinePaint, stroke,
   *               outlineStroke, shape, itemLabelsVisible, itemLabelFont,
   *               itemLabelPaint, positiveItemLabelPosition,
   *               negativeItemLabelPosition and createEntities override
   *               fields (DG);
   * 13-Jun-2007 : Added new autoPopulate flags for core series attributes (DG);
   * 23-Oct-2007 : Updated lookup methods to better handle overridden
   *               methods (DG);
   * 04-Dec-2007 : Modified hashCode() implementation (DG);
   * 29-Apr-2008 : Minor API doc update (DG);
   * 17-Jun-2008 : Added legendShape, legendTextFont and legendTextPaint
   *               attributes (DG);
   * 18-Aug-2008 : Added clearSeriesPaints() and clearSeriesStrokes() (DG);
   * 28-Jan-2009 : Equals method doesn't test Shape equality correctly (DG);
   * 27-Mar-2009 : Added dataBoundsIncludesVisibleSeriesOnly attribute, and
   *               updated renderer events for series visibility changes (DG);
   * 01-Apr-2009 : Factored up the defaultEntityRadius field from the
   *               AbstractXYItemRenderer class (DG);
   * 28-Apr-2009 : Added flag to allow a renderer to treat the legend shape as
   *               a line (DG);
   *
   */
  
  package org.jfree.chart.renderer;
  
  import java.awt.BasicStroke;
  import java.awt.Color;
  import java.awt.Font;
  import java.awt.Paint;
  import java.awt.Shape;
  import java.awt.Stroke;
  import java.awt.geom.Point2D;
  import java.awt.geom.Rectangle2D;
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.io.Serializable;
  import java.util.Arrays;
  import java.util.EventListener;
  import java.util.List;
  
  import javax.swing.event.EventListenerList;
  
  import org.jfree.chart.HashUtilities;
  import org.jfree.chart.ui.TextAnchor;
  import org.jfree.chart.util.BooleanList;
  import org.jfree.chart.util.ObjectList;
  import org.jfree.chart.util.ObjectUtilities;
  import org.jfree.chart.util.PaintList;
  import org.jfree.chart.util.PaintUtilities;
  import org.jfree.chart.util.ShapeList;
  import org.jfree.chart.util.ShapeUtilities;
  import org.jfree.chart.util.StrokeList;
  import org.jfree.chart.event.RendererChangeEvent;
  import org.jfree.chart.event.RendererChangeListener;
  import org.jfree.chart.labels.ItemLabelAnchor;
  import org.jfree.chart.labels.ItemLabelPosition;
  import org.jfree.chart.plot.DrawingSupplier;
  import org.jfree.chart.plot.PlotOrientation;
  import org.jfree.chart.renderer.item.DefaultLabelIRS;
  import org.jfree.chart.renderer.item.DefaultPaintIRS;
  import org.jfree.chart.renderer.item.DefaultShapeIRS;
  import org.jfree.chart.renderer.item.DefaultStrokeIRS;
  import org.jfree.chart.renderer.item.DefaultVisibilityIRS;
  import org.jfree.chart.renderer.item.LabelIRS;
  import org.jfree.chart.renderer.item.PaintIRS;
  import org.jfree.chart.renderer.item.ShapeIRS;
  import org.jfree.chart.renderer.item.StrokeIRS;
  import org.jfree.chart.renderer.item.VisibilityIRS;
  import org.jfree.chart.title.LegendTitle;
  import org.jfree.chart.util.ParamChecks;
  import org.jfree.chart.util.SerialUtilities;
  
  /**
   * Base class providing common services for renderers.  Most methods that update
   * attributes of the renderer will fire a {@link RendererChangeEvent}, which
   * normally means the plot that owns the renderer will receive notification that
   * the renderer has been changed (the plot will, in turn, notify the chart).
   */
  public abstract class AbstractRenderer implements Cloneable, Serializable {
  
      /** For serialization. */
      private static final long serialVersionUID = -828267569428206075L;
  
      /** Zero represented as a <code>Double</code>. */
      public static final Double ZERO = 0.0;
  
      /** The default paint. */
      public static final Paint DEFAULT_PAINT = Color.BLUE;
  
      /** The default outline paint. */
      public static final Paint DEFAULT_OUTLINE_PAINT = Color.GRAY;
  
      /** The default stroke. */
      public static final Stroke DEFAULT_STROKE = new BasicStroke(1.0f);
  
      /** The default outline stroke. */
      public static final Stroke DEFAULT_OUTLINE_STROKE = new BasicStroke(1.0f);
  
      /** The default shape. */
      public static final Shape DEFAULT_SHAPE
              = new Rectangle2D.Double(-3.0, -3.0, 6.0, 6.0);
  
      /** The default value label font. */
      public static final Font DEFAULT_VALUE_LABEL_FONT
              = new Font("SansSerif", Font.PLAIN, 10);
  
      /** The default value label paint. */
      public static final Paint DEFAULT_VALUE_LABEL_PAINT = Color.BLACK;
  
      /** 
       * A hook that allows to control the rendering of individual item labels 
       * (if the renderer uses {@link #getItemLabelFont(int, int)} ... )
       */
      private LabelIRS labelIRS = new DefaultLabelIRS(this);
  
      /** 
       * A hook that allows to control the painting of individual items (if the 
       * renderer uses {@link #getItemPaint(int, int)} ... )
       */
      private PaintIRS paintIRS = new DefaultPaintIRS(this);
  
      /** 
       * A hook that allows to control the shape of individual items
       *  (if the renderer uses {@link #getItemShape(int, int)} ... )
       */
      private ShapeIRS shapeIRS = new DefaultShapeIRS(this);
  
      /** 
       * A hook that allows to use individual strokes for each item 
       * (if the renderer uses {@link #getItemStroke(int, int)} ... )
       */
      private StrokeIRS strokeIRS = new DefaultStrokeIRS(this);
  
      /** 
       * A hook that allows to control the visibility of individual items
       * (if the renderer uses {@link #getItemVisible(int, int)} ... )
       */
      private VisibilityIRS visibilityIRS = new DefaultVisibilityIRS(this);
  
      /** A list of flags that controls whether or not each series is visible. */
      private BooleanList seriesVisibleList;
  
      /** The default visibility for all series. */
      private boolean defaultSeriesVisible;
  
      /**
       * A list of flags that controls whether or not each series is visible in
       * the legend.
       */
      private BooleanList seriesVisibleInLegendList;
  
      /** The default visibility for each series in the legend. */
      private boolean defaultSeriesVisibleInLegend;
  
      /** The paint list. */
      private PaintList paintList;
  
      /**
       * A flag that controls whether or not the paintList is auto-populated
       * in the {@link #lookupSeriesPaint(int)} method.
       *
       * @since 1.0.6
       */
      private boolean autoPopulateSeriesPaint;
  
      /** The base paint. */
      private transient Paint defaultPaint;
  
      /** The fill paint list. */
      private PaintList fillPaintList;
  
      /**
       * A flag that controls whether or not the fillPaintList is auto-populated
       * in the {@link #lookupSeriesFillPaint(int)} method.
       *
       * @since 1.0.6
       */
      private boolean autoPopulateSeriesFillPaint;
  
      /** The base fill paint. */
      private transient Paint defaultFillPaint;
  
      /** The outline paint list. */
      private PaintList outlinePaintList;
  
      /**
       * A flag that controls whether or not the outlinePaintList is
       * auto-populated in the {@link #lookupSeriesOutlinePaint(int)} method.
       *
       * @since 1.0.6
       */
      private boolean autoPopulateSeriesOutlinePaint;
  
      /** The base outline paint. */
      private transient Paint defaultOutlinePaint;
  
      /** The stroke list. */
      private StrokeList strokeList;
  
      /**
       * A flag that controls whether or not the strokeList is auto-populated
       * in the {@link #lookupSeriesStroke(int)} method.
       *
       * @since 1.0.6
       */
      private boolean autoPopulateSeriesStroke;
  
      /** The base stroke. */
      private transient Stroke defaultStroke;
  
      /** The outline stroke list. */
      private StrokeList outlineStrokeList;
  
      /** The base outline stroke. */
      private transient Stroke defaultOutlineStroke;
  
      /**
       * A flag that controls whether or not the outlineStrokeList is
       * auto-populated in the {@link #lookupSeriesOutlineStroke(int)} method.
       *
       * @since 1.0.6
       */
      private boolean autoPopulateSeriesOutlineStroke;
  
      /** A shape list. */
      private ShapeList shapeList;
  
      /**
       * A flag that controls whether or not the shapeList is auto-populated
       * in the {@link #lookupSeriesShape(int)} method.
       *
       * @since 1.0.6
       */
      private boolean autoPopulateSeriesShape;
  
      /** The base shape. */
      private transient Shape defaultShape;
  
      /** Visibility of the item labels PER series. */
      private BooleanList itemLabelsVisibleList;
  
      /** The base item labels visible. */
      private Boolean defaultItemLabelsVisible;
  
      /** The item label font list (one font per series). */
      private ObjectList<Font> itemLabelFontList;
  
      /** The base item label font. */
      private Font defaultItemLabelFont;
  
      /** The item label paint list (one paint per series). */
      private PaintList itemLabelPaintList;
  
      /** The base item label paint. */
      private transient Paint defaultItemLabelPaint;
  
      /** The positive item label position (per series). */
      private ObjectList<ItemLabelPosition> positiveItemLabelPositionList;
  
      /** The fallback positive item label position. */
      private ItemLabelPosition defaultPositiveItemLabelPosition;
  
      /** The negative item label position (per series). */
      private ObjectList<ItemLabelPosition> negativeItemLabelPositionList;
  
      /** The fallback negative item label position. */
      private ItemLabelPosition defaultNegativeItemLabelPosition;
  
      /** The item label anchor offset. */
      private double itemLabelAnchorOffset = 2.0;
  
      /**
       * Flags that control whether or not entities are generated for each
       * series.  This will be overridden by 'createEntities'.
       */
      private BooleanList createEntitiesList;
  
      /**
       * The default flag that controls whether or not entities are generated.
       * This flag is used when both the above flags return null.
       */
      private boolean defaultCreateEntities;
  
      /**
       * The per-series legend shape settings.
       *
       * @since 1.0.11
       */
      private ShapeList legendShapeList;
  
      /**
       * The base shape for legend items.  If this is <code>null</code>, the
       * series shape will be used.
       *
       * @since 1.0.11
       */
      private transient Shape defaultLegendShape;
  
      /**
       * A special flag that, if true, will cause the getLegendItem() method
       * to configure the legend shape as if it were a line.
       *
       * @since 1.0.14
       */
      private boolean treatLegendShapeAsLine;
  
      /**
       * The per-series legend text font.
       *
       * @since 1.0.11
       */
      private ObjectList<Font> legendTextFont;
  
      /**
       * The base legend font.
       *
       * @since 1.0.11
       */
      private Font defaultLegendTextFont;
  
      /**
       * The per series legend text paint settings.
       *
       * @since 1.0.11
       */
      private PaintList legendTextPaint;
  
      /**
       * The default paint for the legend text items (if this is
       * <code>null</code>, the {@link LegendTitle} class will determine the
       * text paint to use.
       *
       * @since 1.0.11
       */
      private transient Paint defaultLegendTextPaint;
  
      /**
       * A flag that controls whether or not the renderer will include the
       * non-visible series when calculating the data bounds.
       *
       * @since 1.0.13
       */
      private boolean dataBoundsIncludesVisibleSeriesOnly = true;
  
      /** The default radius for the entity 'hotspot' */
      private int defaultEntityRadius;
  
      /** Storage for registered change listeners. */
      private transient EventListenerList listenerList;
  
      /** An event for re-use. */
      private transient RendererChangeEvent event;
  
      /**
       * Default constructor.
       */
      public AbstractRenderer() {
  
          this.seriesVisibleList = new BooleanList();
          this.defaultSeriesVisible = true;
  
          this.seriesVisibleInLegendList = new BooleanList();
          this.defaultSeriesVisibleInLegend = true;
  
          this.paintList = new PaintList();
          this.defaultPaint = DEFAULT_PAINT;
          this.autoPopulateSeriesPaint = true;
  
          this.fillPaintList = new PaintList();
          this.defaultFillPaint = Color.WHITE;
          this.autoPopulateSeriesFillPaint = false;
  
          this.outlinePaintList = new PaintList();
          this.defaultOutlinePaint = DEFAULT_OUTLINE_PAINT;
          this.autoPopulateSeriesOutlinePaint = false;
  
          this.strokeList = new StrokeList();
          this.defaultStroke = DEFAULT_STROKE;
          this.autoPopulateSeriesStroke = true;
  
          this.outlineStrokeList = new StrokeList();
          this.defaultOutlineStroke = DEFAULT_OUTLINE_STROKE;
          this.autoPopulateSeriesOutlineStroke = false;
  
          this.shapeList = new ShapeList();
          this.defaultShape = DEFAULT_SHAPE;
          this.autoPopulateSeriesShape = true;
  
          this.itemLabelsVisibleList = new BooleanList();
          this.defaultItemLabelsVisible = Boolean.FALSE;
  
          this.itemLabelFontList = new ObjectList<Font>();
          this.defaultItemLabelFont = new Font("SansSerif", Font.PLAIN, 10);
  
          this.itemLabelPaintList = new PaintList();
          this.defaultItemLabelPaint = Color.BLACK;
  
          this.positiveItemLabelPositionList = new ObjectList<ItemLabelPosition>();
          this.defaultPositiveItemLabelPosition = new ItemLabelPosition(
                  ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER);
  
          this.negativeItemLabelPositionList = new ObjectList<ItemLabelPosition>();
          this.defaultNegativeItemLabelPosition = new ItemLabelPosition(
                  ItemLabelAnchor.OUTSIDE6, TextAnchor.TOP_CENTER);
  
          this.createEntitiesList = new BooleanList();
          this.defaultCreateEntities = true;
  
          this.defaultEntityRadius = 3;
  
          this.legendShapeList = new ShapeList();
          this.defaultLegendShape = null;
  
          this.treatLegendShapeAsLine = false;
  
          this.legendTextFont = new ObjectList<Font>();
          this.defaultLegendTextFont = new Font("Dialog", Font.PLAIN, 12);
  
          this.legendTextPaint = new PaintList();
          this.defaultLegendTextPaint = null;
  
          this.listenerList = new EventListenerList();
  
      }
  
      /**
       * Returns the drawing supplier from the plot.
       *
       * @return The drawing supplier.
       */
      public abstract DrawingSupplier getDrawingSupplier();
          
      // SETTER FOR ITEM RENDERING STRATEGIES
          
      /**
       * @param labelIRS {@link #labelIRS} (<code>null</code> not permitted)
       */
      public void setLabelIRS(LabelIRS labelIRS) {
          ParamChecks.nullNotPermitted(labelIRS, "labelIRS");
          this.labelIRS = labelIRS;
      }
          
      /**
       * @param paintIRS {@link #paintIRS} (<code>null</code> not permitted)
       */
      public void setPaintIRS(PaintIRS paintIRS) {
          ParamChecks.nullNotPermitted(paintIRS, "paintIRS");
          this.paintIRS = paintIRS;
      }
          
      /**
       * @param shapeIRS {@link #shapeIRS} (<code>null</code> not permitted)
       */
      public void setShapeIRS(ShapeIRS shapeIRS) {
          ParamChecks.nullNotPermitted(shapeIRS, "shapeIRS");
          this.shapeIRS = shapeIRS;
      }
          
      /**
       * @param strokeIRS {@link #strokeIRS} (<code>null</code> not permitted)
       */
      public void setStrokeIRS(StrokeIRS strokeIRS) {
          ParamChecks.nullNotPermitted(strokeIRS, "strokeIRS");
          this.strokeIRS = strokeIRS;
      }
         
      /**
       * @param visibilityIRS {@link #visibilityIRS} (<code>null</code> not 
       *     permitted)
       */
      public void setVisibilityIRS(VisibilityIRS visibilityIRS) {
          ParamChecks.nullNotPermitted(visibilityIRS, null);
          this.visibilityIRS = visibilityIRS;
      }
      
      // SERIES VISIBLE (not yet respected by all renderers)
  
      /**
       * Returns a boolean that indicates whether or not the specified item
       * should be drawn (this is typically used to hide an entire series).
       * <p>
       * The default implementation passes control to the 
       * {@link DefaultVisibilityIRS} which uses the 
       * <code>isSeriesVisible(series)</code> method. You can implement your
       * own {@link VisibilityIRS} or override this method if you require 
       * different behavior. 
       *
       * @param series  the series index.
       * @param column  the column (or category) index (zero-based).
       *
       * @return The item visibility
       */
      public boolean getItemVisible(int series, int item) {
          return visibilityIRS.getItemVisible(series, item);
      }
  
      /**
       * Returns a boolean that indicates whether or not the specified series
       * should be drawn.
       *
       * @param series  the series index.
       *
       * @return A boolean.
       */
      public boolean isSeriesVisible(int series) {
          boolean result = this.defaultSeriesVisible;
          Boolean b = this.seriesVisibleList.getBoolean(series);
          if (b != null) {
              result = b;
          }
          return result;
      }
  
      /**
       * Returns the flag that controls whether a series is visible.
       *
       * @param series  the series index (zero-based).
       *
       * @return The flag (possibly <code>null</code>).
       *
       * @see #setSeriesVisible(int, Boolean)
       */
      public Boolean getSeriesVisible(int series) {
          return this.seriesVisibleList.getBoolean(series);
      }
  
      /**
       * Sets the flag that controls whether a series is visible and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param visible  the flag (<code>null</code> permitted).
       *
       * @see #getSeriesVisible(int)
       */
      public void setSeriesVisible(int series, Boolean visible) {
          setSeriesVisible(series, visible, true);
      }
  
      /**
       * Sets the flag that controls whether a series is visible and, if
       * requested, sends a {@link RendererChangeEvent} to all registered
       * listeners.
       *
       * @param series  the series index.
       * @param visible  the flag (<code>null</code> permitted).
       * @param notify  notify listeners?
       *
       * @see #getSeriesVisible(int)
       */
      public void setSeriesVisible(int series, Boolean visible, boolean notify) {
          this.seriesVisibleList.setBoolean(series, visible);
          if (notify) {
              // we create an event with a special flag set...the purpose of
              // this is to communicate to the plot (the default receiver of
              // the event) that series visibility has changed so the axis
              // ranges might need updating...
              RendererChangeEvent e = new RendererChangeEvent(this, true);
              notifyListeners(e);
          }
      }
  
      /**
       * Returns the default visibility for all series.
       *
       * @return The default visibility.
       *
       * @see #setDefaultSeriesVisible(boolean)
       */
      public boolean getDefaultSeriesVisible() {
          return this.defaultSeriesVisible;
      }
  
      /**
       * Sets the default series visibility and sends a 
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param visible  the flag.
       *
       * @see #getDefaultSeriesVisible()
       */
      public void setDefaultSeriesVisible(boolean visible) {
          // defer argument checking...
          setDefaultSeriesVisible(visible, true);
      }
  
      /**
       * Sets the default series visibility and, if requested, sends
       * a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param visible  the visibility.
       * @param notify  notify listeners?
       *
       * @see #getDefaultSeriesVisible()
       */
      public void setDefaultSeriesVisible(boolean visible, boolean notify) {
          this.defaultSeriesVisible = visible;
          if (notify) {
              // we create an event with a special flag set...the purpose of
              // this is to communicate to the plot (the default receiver of
              // the event) that series visibility has changed so the axis
              // ranges might need updating...
              RendererChangeEvent e = new RendererChangeEvent(this, true);
              notifyListeners(e);
          }
      }
  
      // SERIES VISIBLE IN LEGEND (not yet respected by all renderers)
  
      /**
       * Returns <code>true</code> if the series should be shown in the legend,
       * and <code>false</code> otherwise.
       *
       * @param series  the series index.
       *
       * @return A boolean.
       */
      public boolean isSeriesVisibleInLegend(int series) {
          boolean result = this.defaultSeriesVisibleInLegend;
          Boolean b = this.seriesVisibleInLegendList.getBoolean(series);
          if (b != null) {
              result = b;
          }
          return result;
      }
  
      /**
       * Returns the flag that controls whether a series is visible in the
       * legend.  This method returns only the "per series" settings - to
       * incorporate the default settings as well, you need to use the
       * {@link #isSeriesVisibleInLegend(int)} method.
       *
       * @param series  the series index (zero-based).
       *
       * @return The flag (possibly <code>null</code>).
       *
       * @see #setSeriesVisibleInLegend(int, Boolean)
       */
      public Boolean getSeriesVisibleInLegend(int series) {
          return this.seriesVisibleInLegendList.getBoolean(series);
      }
  
      /**
       * Sets the flag that controls whether a series is visible in the legend
       * and sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param visible  the flag (<code>null</code> permitted).
       *
       * @see #getSeriesVisibleInLegend(int)
       */
      public void setSeriesVisibleInLegend(int series, Boolean visible) {
          setSeriesVisibleInLegend(series, visible, true);
      }
  
      /**
       * Sets the flag that controls whether a series is visible in the legend
       * and, if requested, sends a {@link RendererChangeEvent} to all registered
       * listeners.
       *
       * @param series  the series index.
       * @param visible  the flag (<code>null</code> permitted).
       * @param notify  notify listeners?
       *
       * @see #getSeriesVisibleInLegend(int)
       */
      public void setSeriesVisibleInLegend(int series, Boolean visible,
                                           boolean notify) {
          this.seriesVisibleInLegendList.setBoolean(series, visible);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default visibility in the legend for all series.
       *
       * @return The default visibility.
       *
       * @see #setDefaultSeriesVisibleInLegend(boolean)
       */
      public boolean getDefaultSeriesVisibleInLegend() {
          return this.defaultSeriesVisibleInLegend;
      }
  
      /**
       * Sets the default visibility in the legend and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param visible  the flag.
       *
       * @see #getDefaultSeriesVisibleInLegend()
       */
      public void setDefaultSeriesVisibleInLegend(boolean visible) {
          // defer argument checking...
          setDefaultSeriesVisibleInLegend(visible, true);
      }
  
      /**
       * Sets the default visibility in the legend and, if requested, sends
       * a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param visible  the visibility.
       * @param notify  notify listeners?
       *
       * @see #getDefaultSeriesVisibleInLegend()
       */
      public void setDefaultSeriesVisibleInLegend(boolean visible, 
              boolean notify) {
          this.defaultSeriesVisibleInLegend = visible;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      // PAINT
  
      /**
       * Returns the paint used to fill data items as they are drawn.
       * (this is typically the same for an entire series).
       * <p>
       * The default implementation passes control to the {@link DefaultPaintIRS}
       * which uses the <code>lookupSeriesPaint(row)</code> method. You can 
       * implement your own {@link PaintIRS} or override this method if you 
       * require different behavior. 
       *
       * @param row  the row (or series) index (zero-based).
       * @param column  the column (or category) index (zero-based).
       *
       * @return The paint (never <code>null</code>).
       */
      public Paint getItemPaint(int row, int column) {
          return paintIRS.getItemPaint(row, column);
      }
  
      /**
       * Returns the paint used to fill an item drawn by the renderer.
       *
       * @param series  the series index (zero-based).
       *
       * @return The paint (never <code>null</code>).
       *
       * @since 1.0.6
       */
      public Paint lookupSeriesPaint(int series) {
  
          Paint seriesPaint = getSeriesPaint(series);
          if (seriesPaint == null && this.autoPopulateSeriesPaint) {
              DrawingSupplier supplier = getDrawingSupplier();
              if (supplier != null) {
                  seriesPaint = supplier.getNextPaint();
                  setSeriesPaint(series, seriesPaint, false);
              }
          }
          if (seriesPaint == null) {
              seriesPaint = this.defaultPaint;
          }
          return seriesPaint;
  
      }
  
      /**
       * Returns the paint used to fill an item drawn by the renderer.
       *
       * @param series  the series index (zero-based).
       *
       * @return The paint (possibly <code>null</code>).
       *
       * @see #setSeriesPaint(int, Paint)
       */
      public Paint getSeriesPaint(int series) {
          return this.paintList.getPaint(series);
      }
  
      /**
       * Sets the paint used for a series and sends a {@link RendererChangeEvent}
       * to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param paint  the paint (<code>null</code> permitted).
       *
       * @see #getSeriesPaint(int)
       */
      public void setSeriesPaint(int series, Paint paint) {
          setSeriesPaint(series, paint, true);
      }
  
      /**
       * Sets the paint used for a series and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index.
       * @param paint  the paint (<code>null</code> permitted).
       * @param notify  notify listeners?
       *
       * @see #getSeriesPaint(int)
       */
      public void setSeriesPaint(int series, Paint paint, boolean notify) {
          this.paintList.setPaint(series, paint);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Clears the series paint settings for this renderer and, if requested,
       * sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param notify  notify listeners?
       *
       * @since 1.0.11
       */
      public void clearSeriesPaints(boolean notify) {
          this.paintList.clear();
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default paint.
       *
       * @return The default paint (never <code>null</code>).
       *
       * @see #setDefaultPaint(Paint)
       */
      public Paint getDefaultPaint() {
          return this.defaultPaint;
      }
  
      /**
       * Sets the default paint and sends a {@link RendererChangeEvent} to all
       * registered listeners.
       *
       * @param paint  the paint (<code>null</code> not permitted).
       *
       * @see #getDefaultPaint()
       */
      public void setDefaultPaint(Paint paint) {
          // defer argument checking...
          setDefaultPaint(paint, true);
      }
  
      /**
       * Sets the default paint and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param paint  the paint (<code>null</code> not permitted).
       * @param notify  notify listeners?
       *
       * @see #getDefaultPaint()
       */
      public void setDefaultPaint(Paint paint, boolean notify) {
          this.defaultPaint = paint;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the flag that controls whether or not the series paint list is
       * automatically populated when {@link #lookupSeriesPaint(int)} is called.
       *
       * @return A boolean.
       *
       * @since 1.0.6
       *
       * @see #setAutoPopulateSeriesPaint(boolean)
       */
      public boolean getAutoPopulateSeriesPaint() {
          return this.autoPopulateSeriesPaint;
      }
  
      /**
       * Sets the flag that controls whether or not the series paint list is
       * automatically populated when {@link #lookupSeriesPaint(int)} is called.
       *
       * @param auto  the new flag value.
       *
       * @since 1.0.6
       *
       * @see #getAutoPopulateSeriesPaint()
       */
      public void setAutoPopulateSeriesPaint(boolean auto) {
          this.autoPopulateSeriesPaint = auto;
      }
  
      //// FILL PAINT //////////////////////////////////////////////////////////
  
      /**
       * Returns the paint used to fill data items as they are drawn.
       * (this is typically the same for an entire series).
       * <p>
       * The default implementation passes control to the {@link DefaultPaintIRS}
       * which uses the <code>lookupSeriesFillPaint(row)</code> method. You can 
       * implement your own {@link PaintIRS} or override this method if you 
       * require different behavior. 
       *
       * @param row  the row (or series) index (zero-based).
       * @param column  the column (or category) index (zero-based).
       *
       * @return The paint (never <code>null</code>).
       */
      public Paint getItemFillPaint(int row, int column) {
          return paintIRS.getItemFillPaint(row, column);
      }
  
      /**
       * Returns the paint used to fill an item drawn by the renderer.
       *
       * @param series  the series (zero-based index).
       *
       * @return The paint (never <code>null</code>).
       *
       * @since 1.0.6
       */
      public Paint lookupSeriesFillPaint(int series) {
  
          Paint seriesFillPaint = getSeriesFillPaint(series);
          if (seriesFillPaint == null && this.autoPopulateSeriesFillPaint) {
              DrawingSupplier supplier = getDrawingSupplier();
              if (supplier != null) {
                  seriesFillPaint = supplier.getNextFillPaint();
                  setSeriesFillPaint(series, seriesFillPaint, false);
              }
          }
          if (seriesFillPaint == null) {
              seriesFillPaint = this.defaultFillPaint;
          }
          return seriesFillPaint;
  
      }
  
      /**
       * Returns the paint used to fill an item drawn by the renderer.
       *
       * @param series  the series (zero-based index).
       *
       * @return The paint (never <code>null</code>).
       *
       * @see #setSeriesFillPaint(int, Paint)
       */
      public Paint getSeriesFillPaint(int series) {
          return this.fillPaintList.getPaint(series);
      }
  
      /**
       * Sets the paint used for a series fill and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param paint  the paint (<code>null</code> permitted).
       *
       * @see #getSeriesFillPaint(int)
       */
      public void setSeriesFillPaint(int series, Paint paint) {
          setSeriesFillPaint(series, paint, true);
      }
  
      /**
       * Sets the paint used to fill a series and, if requested,
       * sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param paint  the paint (<code>null</code> permitted).
       * @param notify  notify listeners?
       *
       * @see #getSeriesFillPaint(int)
       */
      public void setSeriesFillPaint(int series, Paint paint, boolean notify) {
          this.fillPaintList.setPaint(series, paint);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default fill paint.
       *
       * @return The paint (never <code>null</code>).
       *
       * @see #setDefaultFillPaint(Paint)
       */
      public Paint getDefaultFillPaint() {
          return this.defaultFillPaint;
      }
  
      /**
       * Sets the default fill paint and sends a {@link RendererChangeEvent} to
       * all registered listeners.
       *
       * @param paint  the paint (<code>null</code> not permitted).
       *
       * @see #getDefaultFillPaint()
       */
      public void setDefaultFillPaint(Paint paint) {
          // defer argument checking...
          setDefaultFillPaint(paint, true);
      }
  
      /**
       * Sets the default fill paint and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param paint  the paint (<code>null</code> not permitted).
       * @param notify  notify listeners?
       *
       * @see #getDefaultFillPaint()
       */
      public void setDefaultFillPaint(Paint paint, boolean notify) {
          ParamChecks.nullNotPermitted(paint, "paint");
          this.defaultFillPaint = paint;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the flag that controls whether or not the series fill paint list
       * is automatically populated when {@link #lookupSeriesFillPaint(int)} is
       * called.
       *
       * @return A boolean.
       *
       * @since 1.0.6
       *
       * @see #setAutoPopulateSeriesFillPaint(boolean)
       */
      public boolean getAutoPopulateSeriesFillPaint() {
          return this.autoPopulateSeriesFillPaint;
      }
  
      /**
       * Sets the flag that controls whether or not the series fill paint list is
       * automatically populated when {@link #lookupSeriesFillPaint(int)} is
       * called.
       *
       * @param auto  the new flag value.
       *
       * @since 1.0.6
       *
       * @see #getAutoPopulateSeriesFillPaint()
       */
      public void setAutoPopulateSeriesFillPaint(boolean auto) {
          this.autoPopulateSeriesFillPaint = auto;
      }
  
      // OUTLINE PAINT //////////////////////////////////////////////////////////
  
      /**
       * Returns the paint used to outline data items as they are drawn.
       * (this is typically the same for an entire series).
       * <p>
       * The default implementation passes control to the {@link DefaultPaintIRS}
       * which uses the <code>return lookupSeriesOutlinePaint(row)</code> method. 
       * You can implement your own {@link PaintIRS} or override this method if 
       * you require different behavior. 
       *
       * @param row  the row (or series) index (zero-based).
       * @param column  the column (or category) index (zero-based).
       *
       * @return The paint (never <code>null</code>).
       */
      public Paint getItemOutlinePaint(int row, int column) {
          return paintIRS.getItemOutlinePaint(row, column);
      }
  
      /**
       * Returns the paint used to outline an item drawn by the renderer.
       *
       * @param series  the series (zero-based index).
       *
       * @return The paint (never <code>null</code>).
       *
       * @since 1.0.6
       */
      public Paint lookupSeriesOutlinePaint(int series) {
  
          Paint seriesOutlinePaint = getSeriesOutlinePaint(series);
          if (seriesOutlinePaint == null && this.autoPopulateSeriesOutlinePaint) {
              DrawingSupplier supplier = getDrawingSupplier();
              if (supplier != null) {
                  seriesOutlinePaint = supplier.getNextOutlinePaint();
                  setSeriesOutlinePaint(series, seriesOutlinePaint, false);
              }
          }
          if (seriesOutlinePaint == null) {
              seriesOutlinePaint = this.defaultOutlinePaint;
          }
          return seriesOutlinePaint;
  
      }
  
      /**
       * Returns the paint used to outline an item drawn by the renderer.
       *
       * @param series  the series (zero-based index).
       *
       * @return The paint (possibly <code>null</code>).
       *
       * @see #setSeriesOutlinePaint(int, Paint)
       */
      public Paint getSeriesOutlinePaint(int series) {
          return this.outlinePaintList.getPaint(series);
      }
  
      /**
       * Sets the paint used for a series outline and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param paint  the paint (<code>null</code> permitted).
       *
       * @see #getSeriesOutlinePaint(int)
       */
      public void setSeriesOutlinePaint(int series, Paint paint) {
          setSeriesOutlinePaint(series, paint, true);
      }
  
      /**
       * Sets the paint used to draw the outline for a series and, if requested,
       * sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param paint  the paint (<code>null</code> permitted).
       * @param notify  notify listeners?
       *
       * @see #getSeriesOutlinePaint(int)
       */
      public void setSeriesOutlinePaint(int series, Paint paint, boolean notify) {
          this.outlinePaintList.setPaint(series, paint);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default outline paint.
       *
       * @return The paint (never <code>null</code>).
       *
       * @see #setDefaultOutlinePaint(Paint)
       */
      public Paint getDefaultOutlinePaint() {
          return this.defaultOutlinePaint;
      }
  
      /**
       * Sets the default outline paint and sends a {@link RendererChangeEvent} to
       * all registered listeners.
       *
       * @param paint  the paint (<code>null</code> not permitted).
       *
       * @see #getDefaultOutlinePaint()
       */
      public void setDefaultOutlinePaint(Paint paint) {
          // defer argument checking...
          setDefaultOutlinePaint(paint, true);
      }
  
      /**
       * Sets the default outline paint and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param paint  the paint (<code>null</code> not permitted).
       * @param notify  notify listeners?
       *
       * @see #getDefaultOutlinePaint()
       */
      public void setDefaultOutlinePaint(Paint paint, boolean notify) {
          ParamChecks.nullNotPermitted(paint, "paint");
          this.defaultOutlinePaint = paint;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the flag that controls whether or not the series outline paint
       * list is automatically populated when
       * {@link #lookupSeriesOutlinePaint(int)} is called.
       *
       * @return A boolean.
       *
       * @since 1.0.6
       *
       * @see #setAutoPopulateSeriesOutlinePaint(boolean)
       */
      public boolean getAutoPopulateSeriesOutlinePaint() {
          return this.autoPopulateSeriesOutlinePaint;
      }
  
      /**
       * Sets the flag that controls whether or not the series outline paint list
       * is automatically populated when {@link #lookupSeriesOutlinePaint(int)}
       * is called.
       *
       * @param auto  the new flag value.
       *
       * @since 1.0.6
       *
       * @see #getAutoPopulateSeriesOutlinePaint()
       */
      public void setAutoPopulateSeriesOutlinePaint(boolean auto) {
          this.autoPopulateSeriesOutlinePaint = auto;
      }
  
      // STROKE
  
      /**
       * Returns the stroke used to draw data items.
       * (this is typically the same for an entire series).
       * <p>
       * The default implementation passes control to the {@link DefaultStrokeIRS}
       * which uses the <code>lookupSeriesStroke(row)</code> method. You can 
       * implement your own {@link StrokeIRS} or override this method if you 
       * require different behavior. 
       *
       * @param row  the row (or series) index (zero-based).
       * @param column  the column (or category) index (zero-based).
       *
       * @return The stroke (never <code>null</code>).
       */
      public Stroke getItemStroke(int row, int column) {
          return strokeIRS.getItemStroke(row, column);
      }
  
      /**
       * Returns the stroke used to draw the items in a series.
       *
       * @param series  the series (zero-based index).
       *
       * @return The stroke (never <code>null</code>).
       *
       * @since 1.0.6
       */
      public Stroke lookupSeriesStroke(int series) {
  
          Stroke result = getSeriesStroke(series);
          if (result == null && this.autoPopulateSeriesStroke) {
              DrawingSupplier supplier = getDrawingSupplier();
              if (supplier != null) {
                  result = supplier.getNextStroke();
                  setSeriesStroke(series, result, false);
              }
          }
          if (result == null) {
              result = this.defaultStroke;
          }
          return result;
  
      }
  
      /**
       * Returns the stroke used to draw the items in a series.
       *
       * @param series  the series (zero-based index).
       *
       * @return The stroke (possibly <code>null</code>).
       *
       * @see #setSeriesStroke(int, Stroke)
       */
      public Stroke getSeriesStroke(int series) {
          return this.strokeList.getStroke(series);
      }
  
      /**
       * Sets the stroke used for a series and sends a {@link RendererChangeEvent}
       * to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param stroke  the stroke (<code>null</code> permitted).
       *
       * @see #getSeriesStroke(int)
       */
      public void setSeriesStroke(int series, Stroke stroke) {
          setSeriesStroke(series, stroke, true);
      }
  
      /**
       * Sets the stroke for a series and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param stroke  the stroke (<code>null</code> permitted).
       * @param notify  notify listeners?
       *
       * @see #getSeriesStroke(int)
       */
      public void setSeriesStroke(int series, Stroke stroke, boolean notify) {
          this.strokeList.setStroke(series, stroke);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Clears the series stroke settings for this renderer and, if requested,
       * sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param notify  notify listeners?
       *
       * @since 1.0.11
       */
      public void clearSeriesStrokes(boolean notify) {
          this.strokeList.clear();
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default stroke.
       *
       * @return The default stroke (never <code>null</code>).
       *
       * @see #setDefaultStroke(Stroke)
       */
      public Stroke getDefaultStroke() {
          return this.defaultStroke;
      }
  
      /**
       * Sets the default stroke and sends a {@link RendererChangeEvent} to all
       * registered listeners.
       *
       * @param stroke  the stroke (<code>null</code> not permitted).
       *
       * @see #getDefaultStroke()
       */
      public void setDefaultStroke(Stroke stroke) {
          // defer argument checking...
          setDefaultStroke(stroke, true);
      }
  
      /**
       * Sets the default stroke and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param stroke  the stroke (<code>null</code> not permitted).
       * @param notify  notify listeners?
       *
       * @see #getDefaultStroke()
       */
      public void setDefaultStroke(Stroke stroke, boolean notify) {
          ParamChecks.nullNotPermitted(stroke, "stroke");
          this.defaultStroke = stroke;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the flag that controls whether or not the series stroke list is
       * automatically populated when {@link #lookupSeriesStroke(int)} is called.
       *
       * @return A boolean.
       *
       * @since 1.0.6
       *
       * @see #setAutoPopulateSeriesStroke(boolean)
       */
      public boolean getAutoPopulateSeriesStroke() {
          return this.autoPopulateSeriesStroke;
      }
  
      /**
       * Sets the flag that controls whether or not the series stroke list is
       * automatically populated when {@link #lookupSeriesStroke(int)} is called.
       *
       * @param auto  the new flag value.
       *
       * @since 1.0.6
       *
       * @see #getAutoPopulateSeriesStroke()
       */
      public void setAutoPopulateSeriesStroke(boolean auto) {
          this.autoPopulateSeriesStroke = auto;
      }
  
      // OUTLINE STROKE
  
      /**
       * Returns the stroke used to outline data items
       * (this is typically the same for an entire series).
       * <p>
       * The default implementation passes control to the {@link DefaultStrokeIRS}
       * which uses the <code>lookupSeriesOutlineStroke(row)</code> method. You 
       * can implement your own {@link StrokeIRS} or override this method if you
       * require different behavior. 
       *
       * @param row  the row (or series) index (zero-based).
       * @param column  the column (or category) index (zero-based).
       *
       * @return The stroke (never <code>null</code>).
       */
      public Stroke getItemOutlineStroke(int row, int column) {
          return strokeIRS.getItemOutlineStroke(row, column);
      }
  
      /**
       * Returns the stroke used to outline the items in a series.
       *
       * @param series  the series (zero-based index).
       *
       * @return The stroke (never <code>null</code>).
       *
       * @since 1.0.6
       */
      public Stroke lookupSeriesOutlineStroke(int series) {
  
          Stroke result = getSeriesOutlineStroke(series);
          if (result == null && this.autoPopulateSeriesOutlineStroke) {
              DrawingSupplier supplier = getDrawingSupplier();
              if (supplier != null) {
                  result = supplier.getNextOutlineStroke();
                  setSeriesOutlineStroke(series, result, false);
              }
          }
          if (result == null) {
              result = this.defaultOutlineStroke;
          }
          return result;
  
      }
  
      /**
       * Returns the stroke used to outline the items in a series.
       *
       * @param series  the series (zero-based index).
       *
       * @return The stroke (possibly <code>null</code>).
       *
       * @see #setSeriesOutlineStroke(int, Stroke)
       */
      public Stroke getSeriesOutlineStroke(int series) {
          return this.outlineStrokeList.getStroke(series);
      }
  
      /**
       * Sets the outline stroke used for a series and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param stroke  the stroke (<code>null</code> permitted).
       *
       * @see #getSeriesOutlineStroke(int)
       */
      public void setSeriesOutlineStroke(int series, Stroke stroke) {
          setSeriesOutlineStroke(series, stroke, true);
      }
  
      /**
       * Sets the outline stroke for a series and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index.
       * @param stroke  the stroke (<code>null</code> permitted).
       * @param notify  notify listeners?
       *
       * @see #getSeriesOutlineStroke(int)
       */
      public void setSeriesOutlineStroke(int series, Stroke stroke,
                                         boolean notify) {
          this.outlineStrokeList.setStroke(series, stroke);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default outline stroke.
       *
       * @return The stroke (never <code>null</code>).
       *
       * @see #setDefaultOutlineStroke(Stroke)
       */
      public Stroke getDefaultOutlineStroke() {
          return this.defaultOutlineStroke;
      }
  
      /**
       * Sets the default outline stroke and sends a {@link RendererChangeEvent} 
       * to all registered listeners.
       *
       * @param stroke  the stroke (<code>null</code> not permitted).
       *
       * @see #getDefaultOutlineStroke()
       */
      public void setDefaultOutlineStroke(Stroke stroke) {
          setDefaultOutlineStroke(stroke, true);
      }
  
      /**
       * Sets the default outline stroke and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param stroke  the stroke (<code>null</code> not permitted).
       * @param notify  a flag that controls whether or not listeners are
       *                notified.
       *
       * @see #getDefaultOutlineStroke()
       */
      public void setDefaultOutlineStroke(Stroke stroke, boolean notify) {
          ParamChecks.nullNotPermitted(stroke, "stroke");
          this.defaultOutlineStroke = stroke;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the flag that controls whether or not the series outline stroke
       * list is automatically populated when
       * {@link #lookupSeriesOutlineStroke(int)} is called.
       *
       * @return A boolean.
       *
       * @since 1.0.6
       *
       * @see #setAutoPopulateSeriesOutlineStroke(boolean)
       */
      public boolean getAutoPopulateSeriesOutlineStroke() {
          return this.autoPopulateSeriesOutlineStroke;
      }
  
      /**
       * Sets the flag that controls whether or not the series outline stroke list
       * is automatically populated when {@link #lookupSeriesOutlineStroke(int)}
       * is called.
       *
       * @param auto  the new flag value.
       *
       * @since 1.0.6
       *
       * @see #getAutoPopulateSeriesOutlineStroke()
       */
      public void setAutoPopulateSeriesOutlineStroke(boolean auto) {
          this.autoPopulateSeriesOutlineStroke = auto;
      }
  
      // SHAPE
  
      /**
       *  Returns a shape used to represent a data item.
       * (this is typically the same for an entire series).
       * <p>
       * The default implementation passes control to the {@link DefaultShapeIRS}
       * which uses the <code>lookupSeriesShape(row)</code> method. You can 
       * implement your own {@link ShapeIRS} or override this method if you 
       * require different behavior. 
       *
       * @param row  the row (or series) index (zero-based).
       * @param column  the column (or category) index (zero-based).
       *
       * @return The shape (never <code>null</code>).
       */
      public Shape getItemShape(int row, int column) {
          return shapeIRS.getItemShape(row, column);
      }
  
      /**
       * Returns a shape used to represent the items in a series.
       *
       * @param series  the series (zero-based index).
       *
       * @return The shape (never <code>null</code>).
       *
       * @since 1.0.6
       */
      public Shape lookupSeriesShape(int series) {
  
          Shape result = getSeriesShape(series);
          if (result == null && this.autoPopulateSeriesShape) {
              DrawingSupplier supplier = getDrawingSupplier();
              if (supplier != null) {
                  result = supplier.getNextShape();
                  setSeriesShape(series, result, false);
              }
          }
          if (result == null) {
              result = this.defaultShape;
          }
          return result;
  
      }
  
      /**
       * Returns a shape used to represent the items in a series.
       *
       * @param series  the series (zero-based index).
       *
       * @return The shape (possibly <code>null</code>).
       *
       * @see #setSeriesShape(int, Shape)
       */
      public Shape getSeriesShape(int series) {
          return this.shapeList.getShape(series);
      }
  
      /**
       * Sets the shape used for a series and sends a {@link RendererChangeEvent}
       * to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param shape  the shape (<code>null</code> permitted).
       *
       * @see #getSeriesShape(int)
       */
      public void setSeriesShape(int series, Shape shape) {
          setSeriesShape(series, shape, true);
      }
  
      /**
       * Sets the shape for a series and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero based).
       * @param shape  the shape (<code>null</code> permitted).
       * @param notify  notify listeners?
       *
       * @see #getSeriesShape(int)
       */
      public void setSeriesShape(int series, Shape shape, boolean notify) {
          this.shapeList.setShape(series, shape);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default shape.
       *
       * @return The shape (never <code>null</code>).
       *
       * @see #setDefaultShape(Shape)
       */
      public Shape getDefaultShape() {
          return this.defaultShape;
      }
  
      /**
       * Sets the default shape and sends a {@link RendererChangeEvent} to all
       * registered listeners.
       *
       * @param shape  the shape (<code>null</code> not permitted).
       *
       * @see #getDefaultShape()
       */
      public void setDefaultShape(Shape shape) {
          // defer argument checking...
          setDefaultShape(shape, true);
      }
  
      /**
       * Sets the default shape and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param shape  the shape (<code>null</code> not permitted).
       * @param notify  notify listeners?
       *
       * @see #getDefaultShape()
       */
      public void setDefaultShape(Shape shape, boolean notify) {
          ParamChecks.nullNotPermitted(shape, "shape");
          this.defaultShape = shape;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the flag that controls whether or not the series shape list is
       * automatically populated when {@link #lookupSeriesShape(int)} is called.
       *
       * @return A boolean.
       *
       * @since 1.0.6
       *
       * @see #setAutoPopulateSeriesShape(boolean)
       */
      public boolean getAutoPopulateSeriesShape() {
          return this.autoPopulateSeriesShape;
      }
  
      /**
       * Sets the flag that controls whether or not the series shape list is
       * automatically populated when {@link #lookupSeriesShape(int)} is called.
       *
       * @param auto  the new flag value.
       *
       * @since 1.0.6
       *
       * @see #getAutoPopulateSeriesShape()
       */
      public void setAutoPopulateSeriesShape(boolean auto) {
          this.autoPopulateSeriesShape = auto;
      }
  
      // ITEM LABEL VISIBILITY...
  
      /**
       * Returns <code>true</code> if an item label is visible, and
       * <code>false</code> otherwise (this is typically the same for an entire 
       * series).
       * <p>
       * The default implementation passes control to the 
       * {@link DefaultVisibilityIRS} which uses the 
       * <code>isSeriesItemLabelsVisible(row)</code> method. You can implement 
       * your own {@link VisibilityIRS} or override this method if you require 
       * different behavior. 
       *
       * @param row  the row (or series) index (zero-based).
       * @param column  the column (or category) index (zero-based).
       *
       * @return true if the item label is visible
       */
      public boolean isItemLabelVisible(int row, int column) {
          return labelIRS.isItemLabelVisible(row, column);
      }
  
      /**
       * Returns <code>true</code> if the item labels for a series are visible,
       * and <code>false</code> otherwise.
       *
       * @param series  the series index (zero-based).
       *
       * @return A boolean.
       */
      public boolean isSeriesItemLabelsVisible(int series) {
          Boolean b = this.itemLabelsVisibleList.getBoolean(series);
          if (b == null) {
              b = this.defaultItemLabelsVisible;
          }
          if (b == null) {
              b = Boolean.FALSE;
          }
          return b;
      }
  
      /**
       * Sets a flag that controls the visibility of the item labels for a series,
       * and sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param visible  the flag.
       */
      public void setSeriesItemLabelsVisible(int series, boolean visible) {
          setSeriesItemLabelsVisible(series, Boolean.valueOf(visible));
      }
  
      /**
       * Sets the visibility of the item labels for a series and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param visible  the flag (<code>null</code> permitted).
       */
      public void setSeriesItemLabelsVisible(int series, Boolean visible) {
          setSeriesItemLabelsVisible(series, visible, true);
      }
  
      /**
       * Sets the visibility of item labels for a series and, if requested, sends
       * a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param visible  the visible flag.
       * @param notify  a flag that controls whether or not listeners are
       *                notified.
       */
      public void setSeriesItemLabelsVisible(int series, Boolean visible,
                                             boolean notify) {
          this.itemLabelsVisibleList.setBoolean(series, visible);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default setting for item label visibility.
       *
       * @return A flag (possibly <code>null</code>).
       *
       * @see #setDefaultItemLabelsVisible(boolean)
       */
      public boolean getDefaultItemLabelsVisible() {
          return this.defaultItemLabelsVisible;
      }
  
      /**
       * Sets the default flag that controls whether or not item labels are 
       * visible, and sends a {@link RendererChangeEvent} to all registered 
       * listeners.
       *
       * @param visible  the flag.
       *
       * @see #getDefaultItemLabelsVisible()
       */
      public void setDefaultItemLabelsVisible(boolean visible) {
          setDefaultItemLabelsVisible(visible, true);
      }
  
      /**
       * Sets the base visibility for item labels and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param visible  the flag (<code>null</code> is permitted, and viewed
       *     as equivalent to <code>Boolean.FALSE</code>).
       * @param notify  a flag that controls whether or not listeners are
       *                notified.
       *
       * @see #getBaseItemLabelsVisible()
       */
      public void setDefaultItemLabelsVisible(boolean visible, boolean notify) {
          this.defaultItemLabelsVisible = visible;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      //// ITEM LABEL FONT //////////////////////////////////////////////////////
  
      /**
       * Returns the font for an item label (this is typically the same for an 
       * entire series).
       * <p>
       * The default implementation passes control to the {@link DefaultLabelIRS}
       * You can implement your own {@link LabelIRS} or override this method if 
       * you require different behavior. 
       *
       * @param row  the row (or series) index (zero-based).
       * @param column  the column (or category) index (zero-based).
       *
       * @return The font (never <code>null</code>).
       */
      public Font getItemLabelFont(int row, int column) {
          return labelIRS.getItemLabelFont(row, column);
      }
  
      /**
       * Returns the font for all the item labels in a series.
       *
       * @param series  the series index (zero-based).
       *
       * @return The font (possibly <code>null</code>).
       *
       * @see #setSeriesItemLabelFont(int, Font)
       */
      public Font getSeriesItemLabelFont(int series) {
          return this.itemLabelFontList.get(series);
      }
  
      /**
       * Sets the item label font for a series and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param font  the font (<code>null</code> permitted).
       *
       * @see #getSeriesItemLabelFont(int)
       */
      public void setSeriesItemLabelFont(int series, Font font) {
          setSeriesItemLabelFont(series, font, true);
      }
  
      /**
       * Sets the item label font for a series and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero based).
       * @param font  the font (<code>null</code> permitted).
       * @param notify  a flag that controls whether or not listeners are
       *                notified.
       *
       * @see #getSeriesItemLabelFont(int)
       */
      public void setSeriesItemLabelFont(int series, Font font, boolean notify) {
          this.itemLabelFontList.set(series, font);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default item label font (this is used when no other font
       * setting is available).
       *
       * @return The font (<code>never</code> null).
       *
       * @see #setDefaultItemLabelFont(Font)
       */
      public Font getDefaultItemLabelFont() {
          return this.defaultItemLabelFont;
      }
  
      /**
       * Sets the default item label font and sends a {@link RendererChangeEvent} 
       * to all registered listeners.
       *
       * @param font  the font (<code>null</code> not permitted).
       *
       * @see #getDefaultItemLabelFont()
       */
      public void setDefaultItemLabelFont(Font font) {
          ParamChecks.nullNotPermitted(font, "font");
          setDefaultItemLabelFont(font, true);
      }
  
      /**
       * Sets the default item label font and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param font  the font (<code>null</code> not permitted).
       * @param notify  a flag that controls whether or not listeners are
       *                notified.
       *
       * @see #getDefaultItemLabelFont()
       */
      public void setDefaultItemLabelFont(Font font, boolean notify) {
          this.defaultItemLabelFont = font;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      //// ITEM LABEL PAINT  ////////////////////////////////////////////////////
  
      /**
       * Returns the paint used to draw an item label.
       *
       * @param row  the row index (zero based).
       * @param column  the column index (zero based).
       *
       * @return The paint (never <code>null</code>).
       */
      public Paint getItemLabelPaint(int row, int column) {
          Paint result = getSeriesItemLabelPaint(row);
          if (result == null) {
              result = this.defaultItemLabelPaint;
          }
          return result;
      }
  
      /**
       * Returns the paint used to draw the item labels for a series.
       *
       * @param series  the series index (zero based).
       *
       * @return The paint (possibly <code>null</code>).
       *
       * @see #setSeriesItemLabelPaint(int, Paint)
       */
      public Paint getSeriesItemLabelPaint(int series) {
          return this.itemLabelPaintList.getPaint(series);
      }
  
      /**
       * Sets the item label paint for a series and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series (zero based index).
       * @param paint  the paint (<code>null</code> permitted).
       *
       * @see #getSeriesItemLabelPaint(int)
       */
      public void setSeriesItemLabelPaint(int series, Paint paint) {
          setSeriesItemLabelPaint(series, paint, true);
      }
  
      /**
       * Sets the item label paint for a series and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero based).
       * @param paint  the paint (<code>null</code> permitted).
       * @param notify  a flag that controls whether or not listeners are
       *                notified.
       *
       * @see #getSeriesItemLabelPaint(int)
       */
      public void setSeriesItemLabelPaint(int series, Paint paint,
                                          boolean notify) {
          this.itemLabelPaintList.setPaint(series, paint);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default item label paint.
       *
       * @return The paint (never <code>null</code>).
       *
       * @see #setDefaultItemLabelPaint(Paint)
       */
      public Paint getDefaultItemLabelPaint() {
          return this.defaultItemLabelPaint;
      }
  
      /**
       * Sets the default item label paint and sends a {@link RendererChangeEvent}
       * to all registered listeners.
       *
       * @param paint  the paint (<code>null</code> not permitted).
       *
       * @see #getDefaultItemLabelPaint()
       */
      public void setDefaultItemLabelPaint(Paint paint) {
          // defer argument checking...
          setDefaultItemLabelPaint(paint, true);
      }
  
      /**
       * Sets the default item label paint and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners..
       *
       * @param paint  the paint (<code>null</code> not permitted).
       * @param notify  a flag that controls whether or not listeners are
       *                notified.
       *
       * @see #getDefaultItemLabelPaint()
       */
      public void setDefaultItemLabelPaint(Paint paint, boolean notify) {
          ParamChecks.nullNotPermitted(paint, "paint");
          this.defaultItemLabelPaint = paint;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      // POSITIVE ITEM LABEL POSITION...
  
      /**
       * Returns the item label position for positive values (this is typically 
       * the same for an entire series).
       * <p>
       * The default implementation passes control to the {@link DefaultLabelIRS}
       * You can implement your own {@link LabelIRS} or override this method if 
       * you require different behavior. 
       *
       * @param row  the row (or series) index (zero-based).
       * @param column  the column (or category) index (zero-based).
       *
       * @return The item label position (never <code>null</code>).
       *
       * @see #getNegativeItemLabelPosition(int, int)
       */
      public ItemLabelPosition getPositiveItemLabelPosition(int row, int column) {
          return labelIRS.getPositiveItemLabelPosition(row, column);
      }
  
      /**
       * Returns the item label position for all positive values in a series.
       *
       * @param series  the series index (zero-based).
       *
       * @return The item label position (never <code>null</code>).
       *
       * @see #setSeriesPositiveItemLabelPosition(int, ItemLabelPosition)
       */
      public ItemLabelPosition getSeriesPositiveItemLabelPosition(int series) {
  
          ItemLabelPosition position 
                  = this.positiveItemLabelPositionList.get(series);
          if (position == null) {
              position = this.defaultPositiveItemLabelPosition;
          }
          return position;
  
      }
  
      /**
       * Sets the item label position for all positive values in a series and
       * sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param position  the position (<code>null</code> permitted).
       *
       * @see #getSeriesPositiveItemLabelPosition(int)
       */
      public void setSeriesPositiveItemLabelPosition(int series,
              ItemLabelPosition position) {
          setSeriesPositiveItemLabelPosition(series, position, true);
      }
  
      /**
       * Sets the item label position for all positive values in a series and (if
       * requested) sends a {@link RendererChangeEvent} to all registered
       * listeners.
       *
       * @param series  the series index (zero-based).
       * @param position  the position (<code>null</code> permitted).
       * @param notify  notify registered listeners?
       *
       * @see #getSeriesPositiveItemLabelPosition(int)
       */
      public void setSeriesPositiveItemLabelPosition(int series,
              ItemLabelPosition position, boolean notify) {
          this.positiveItemLabelPositionList.set(series, position);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default positive item label position.
       *
       * @return The position (never <code>null</code>).
       *
       * @see #setDefaultPositiveItemLabelPosition(ItemLabelPosition)
       */
      public ItemLabelPosition getDefaultPositiveItemLabelPosition() {
          return this.defaultPositiveItemLabelPosition;
      }
  
      /**
       * Sets the default positive item label position.
       *
       * @param position  the position (<code>null</code> not permitted).
       *
       * @see #getDefaultPositiveItemLabelPosition()
       */
      public void setDefaultPositiveItemLabelPosition(
              ItemLabelPosition position) {
          // defer argument checking...
          setDefaultPositiveItemLabelPosition(position, true);
      }
  
      /**
       * Sets the default positive item label position and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param position  the position (<code>null</code> not permitted).
       * @param notify  notify registered listeners?
       *
       * @see #getDefaultPositiveItemLabelPosition()
       */
      public void setDefaultPositiveItemLabelPosition(ItemLabelPosition position,
              boolean notify) {
          ParamChecks.nullNotPermitted(position, "positions");
          this.defaultPositiveItemLabelPosition = position;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      // NEGATIVE ITEM LABEL POSITION...
  
      /**
       * Returns the item label position for negative values (this is typically 
       * the same for an entire series).
      * <p>
       * The default implementation passes control to the {@link DefaultLabelIRS}
       * You can implement your own {@link LabelIRS} or override this method if 
       * you require different behavior. 
       *
       * @param row  the row (or series) index (zero-based).
       * @param column  the column (or category) index (zero-based).
       *
       * @return The item label position (never <code>null</code>).
       *
       * @see #getPositiveItemLabelPosition(int, int)
       */
      public ItemLabelPosition getNegativeItemLabelPosition(int row, int column) {
          return labelIRS.getNegativeItemLabelPosition(row, column);
      }
  
      /**
       * Returns the item label position for all negative values in a series.
       *
       * @param series  the series index (zero-based).
       *
       * @return The item label position (never <code>null</code>).
       *
       * @see #setSeriesNegativeItemLabelPosition(int, ItemLabelPosition)
       */
      public ItemLabelPosition getSeriesNegativeItemLabelPosition(int series) {
  
          ItemLabelPosition position = this.negativeItemLabelPositionList.get(
                  series);
          if (position == null) {
              position = this.defaultNegativeItemLabelPosition;
          }
          return position;
  
      }
  
      /**
       * Sets the item label position for negative values in a series and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param position  the position (<code>null</code> permitted).
       *
       * @see #getSeriesNegativeItemLabelPosition(int)
       */
      public void setSeriesNegativeItemLabelPosition(int series,
              ItemLabelPosition position) {
          setSeriesNegativeItemLabelPosition(series, position, true);
      }
  
      /**
       * Sets the item label position for negative values in a series and (if
       * requested) sends a {@link RendererChangeEvent} to all registered
       * listeners.
       *
       * @param series  the series index (zero-based).
       * @param position  the position (<code>null</code> permitted).
       * @param notify  notify registered listeners?
       *
       * @see #getSeriesNegativeItemLabelPosition(int)
       */
      public void setSeriesNegativeItemLabelPosition(int series,
              ItemLabelPosition position, boolean notify) {
          this.negativeItemLabelPositionList.set(series, position);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default item label position for negative values.
       *
       * @return The position (never <code>null</code>).
       *
       * @see #setDefaultNegativeItemLabelPosition(ItemLabelPosition)
       */
      public ItemLabelPosition getDefaultNegativeItemLabelPosition() {
          return this.defaultNegativeItemLabelPosition;
      }
  
      /**
       * Sets the default item label position for negative values and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param position  the position (<code>null</code> not permitted).
       *
       * @see #getDefaultNegativeItemLabelPosition()
       */
      public void setDefaultNegativeItemLabelPosition(
              ItemLabelPosition position) {
          setDefaultNegativeItemLabelPosition(position, true);
      }
  
      /**
       * Sets the default negative item label position and, if requested, sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param position  the position (<code>null</code> not permitted).
       * @param notify  notify registered listeners?
       *
       * @see #getDefaultNegativeItemLabelPosition()
       */
      public void setDefaultNegativeItemLabelPosition(ItemLabelPosition position,
              boolean notify) {
          ParamChecks.nullNotPermitted(position, "positions");
          this.defaultNegativeItemLabelPosition = position;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the item label anchor offset.
       *
       * @return The offset.
       *
       * @see #setItemLabelAnchorOffset(double)
       */
      public double getItemLabelAnchorOffset() {
          return this.itemLabelAnchorOffset;
      }
  
      /**
       * Sets the item label anchor offset.
       *
       * @param offset  the offset.
       *
       * @see #getItemLabelAnchorOffset()
       */
      public void setItemLabelAnchorOffset(double offset) {
          this.itemLabelAnchorOffset = offset;
          fireChangeEvent();
      }
  
      /**
       * Returns a boolean that indicates whether or not the specified item
       * should have a chart entity created for it.
       *
       * @param series  the series index.
       * @param item  the item index.
       *
       * @return A boolean.
       */
      public boolean getItemCreateEntity(int series, int item) {
          Boolean b = getSeriesCreateEntities(series);
          if (b != null) {
              return b;
          }
          // otherwise...
          return this.defaultCreateEntities;
      }
  
      /**
       * Returns the flag that controls whether entities are created for a
       * series.
       *
       * @param series  the series index (zero-based).
       *
       * @return The flag (possibly <code>null</code>).
       *
       * @see #setSeriesCreateEntities(int, Boolean)
       */
      public Boolean getSeriesCreateEntities(int series) {
          return this.createEntitiesList.getBoolean(series);
      }
  
      /**
       * Sets the flag that controls whether entities are created for a series,
       * and sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index (zero-based).
       * @param create  the flag (<code>null</code> permitted).
       *
       * @see #getSeriesCreateEntities(int)
       */
      public void setSeriesCreateEntities(int series, Boolean create) {
          setSeriesCreateEntities(series, create, true);
      }
  
      /**
       * Sets the flag that controls whether entities are created for a series
       * and, if requested, sends a {@link RendererChangeEvent} to all registered
       * listeners.
       *
       * @param series  the series index.
       * @param create  the flag (<code>null</code> permitted).
       * @param notify  notify listeners?
       *
       * @see #getSeriesCreateEntities(int)
       */
      public void setSeriesCreateEntities(int series, Boolean create,
                                          boolean notify) {
          this.createEntitiesList.setBoolean(series, create);
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the default flag for creating entities.
       *
       * @return The default flag for creating entities.
       *
       * @see #setDefaultCreateEntities(boolean)
       */
      public boolean getDefaultCreateEntities() {
          return this.defaultCreateEntities;
      }
  
      /**
       * Sets the default flag that controls whether entities are created
       * for a series, and sends a {@link RendererChangeEvent}
       * to all registered listeners.
       *
       * @param create  the flag.
       *
       * @see #getDefaultCreateEntities()
       */
      public void setDefaultCreateEntities(boolean create) {
          // defer argument checking...
          setDefaultCreateEntities(create, true);
      }
  
      /**
       * Sets the default flag that controls whether entities are created and,
       * if requested, sends a {@link RendererChangeEvent} to all registered
       * listeners.
       *
       * @param create  the visibility.
       * @param notify  notify listeners?
       *
       * @see #getDefaultCreateEntities()
       */
      public void setDefaultCreateEntities(boolean create, boolean notify) {
          this.defaultCreateEntities = create;
          if (notify) {
              fireChangeEvent();
          }
      }
  
      /**
       * Returns the radius of the circle used for the default entity area
       * when no area is specified.
       *
       * @return A radius.
       *
       * @see #setDefaultEntityRadius(int)
       */
      public int getDefaultEntityRadius() {
          return this.defaultEntityRadius;
      }
  
      /**
       * Sets the radius of the circle used for the default entity area
       * when no area is specified.
       *
       * @param radius  the radius.
       *
       * @see #getDefaultEntityRadius()
       */
      public void setDefaultEntityRadius(int radius) {
          this.defaultEntityRadius = radius;
      }
  
      /**
       * Performs a lookup for the legend shape.
       *
       * @param series  the series index.
       *
       * @return The shape (possibly <code>null</code>).
       *
       * @since 1.0.11
       */
      public Shape lookupLegendShape(int series) {
          Shape result = getLegendShape(series);
          if (result == null) {
              result = this.defaultLegendShape;
          }
          if (result == null) {
              result = lookupSeriesShape(series);
          }
          return result;
      }
  
      /**
       * Returns the legend shape defined for the specified series (possibly
       * <code>null</code>).
       *
       * @param series  the series index.
       *
       * @return The shape (possibly <code>null</code>).
       *
       * @see #lookupLegendShape(int)
       *
       * @since 1.0.11
       */
      public Shape getLegendShape(int series) {
          return this.legendShapeList.getShape(series);
      }
  
      /**
       * Sets the shape used for the legend item for the specified series, and
       * sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index.
       * @param shape  the shape (<code>null</code> permitted).
       *
       * @since 1.0.11
       */
      public void setLegendShape(int series, Shape shape) {
          this.legendShapeList.setShape(series, shape);
          fireChangeEvent();
      }
  
      /**
       * Returns the default legend shape, which may be <code>null</code>.
       *
       * @return The default legend shape.
       *
       * @since 1.0.11
       */
      public Shape getDefaultLegendShape() {
          return this.defaultLegendShape;
      }
  
      /**
       * Sets the default legend shape and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param shape  the shape (<code>null</code> permitted).
       *
       * @since 1.0.11
       */
      public void setDefaultLegendShape(Shape shape) {
          this.defaultLegendShape = shape;
          fireChangeEvent();
      }
  
      /**
       * Returns the flag that controls whether or not the legend shape is
       * treated as a line when creating legend items.
       *
       * @return A boolean.
       *
       * @since 1.0.14
       */
      protected boolean getTreatLegendShapeAsLine() {
          return this.treatLegendShapeAsLine;
      }
  
      /**
       * Sets the flag that controls whether or not the legend shape is
       * treated as a line when creating legend items.
       *
       * @param treatAsLine  the new flag value.
       *
       * @since 1.0.14
       */
      protected void setTreatLegendShapeAsLine(boolean treatAsLine) {
          if (this.treatLegendShapeAsLine != treatAsLine) {
              this.treatLegendShapeAsLine = treatAsLine;
              fireChangeEvent();
          }
      }
  
      /**
       * Performs a lookup for the legend text font.
       *
       * @param series  the series index.
       *
       * @return The font.
       *
       * @since 1.0.11
       */
      public Font lookupLegendTextFont(int series) {
          Font result = getLegendTextFont(series);
          if (result == null) {
              result = this.defaultLegendTextFont;
          }
          return result;
      }
  
      /**
       * Returns the legend text font defined for the specified series (possibly
       * <code>null</code>).
       *
       * @param series  the series index.
       *
       * @return The font (possibly <code>null</code>).
       *
       * @see #lookupLegendTextFont(int)
       *
       * @since 1.0.11
       */
      public Font getLegendTextFont(int series) {
          return this.legendTextFont.get(series);
      }
  
      /**
       * Sets the font used for the legend text for the specified series, and
       * sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index.
       * @param font  the font (<code>null</code> permitted).
       *
       * @since 1.0.11
       */
      public void setLegendTextFont(int series, Font font) {
          this.legendTextFont.set(series, font);
          fireChangeEvent();
      }
  
      /**
       * Returns the default legend text font.
       *
       * @return The default legend text font.
       *
       * @since 1.0.11
       */
      public Font getDefaultLegendTextFont() {
          return this.defaultLegendTextFont;
      }
  
      /**
       * Sets the default legend text font and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param font  the font (<code>null</code> not permitted).
       *
       * @since 1.0.11
       */
      public void setDefaultLegendTextFont(Font font) {
          ParamChecks.nullNotPermitted(font, "font");
          this.defaultLegendTextFont = font;
          fireChangeEvent();
      }
  
      /**
       * Performs a lookup for the legend text paint.
       *
       * @param series  the series index.
       *
       * @return The paint (possibly <code>null</code>).
       *
       * @since 1.0.11
       */
      public Paint lookupLegendTextPaint(int series) {
          Paint result = getLegendTextPaint(series);
          if (result == null) {
              result = this.defaultLegendTextPaint;
          }
          return result;
      }
  
      /**
       * Returns the legend text paint defined for the specified series (possibly
       * <code>null</code>).
       *
       * @param series  the series index.
       *
       * @return The paint (possibly <code>null</code>).
       *
       * @see #lookupLegendTextPaint(int)
       *
       * @since 1.0.11
       */
      public Paint getLegendTextPaint(int series) {
          return this.legendTextPaint.getPaint(series);
      }
  
      /**
       * Sets the paint used for the legend text for the specified series, and
       * sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @param series  the series index.
       * @param paint  the paint (<code>null</code> permitted).
       *
       * @since 1.0.11
       */
      public void setLegendTextPaint(int series, Paint paint) {
          this.legendTextPaint.setPaint(series, paint);
          fireChangeEvent();
      }
  
      /**
       * Returns the default legend text paint, which may be <code>null</code>.
       *
       * @return The default legend text paint.
       *
       * @since 1.0.11
       */
      public Paint getDefaultLegendTextPaint() {
          return this.defaultLegendTextPaint;
      }
  
      /**
       * Sets the default legend text paint and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param paint  the paint (<code>null</code> permitted).
       *
       * @since 1.0.11
       */
      public void setDefaultLegendTextPaint(Paint paint) {
          this.defaultLegendTextPaint = paint;
          fireChangeEvent();
      }
  
      /**
       * Returns the flag that controls whether or not the data bounds reported
       * by this renderer will exclude non-visible series.
       *
       * @return A boolean.
       *
       * @since 1.0.13
       */
      public boolean getDataBoundsIncludesVisibleSeriesOnly() {
          return this.dataBoundsIncludesVisibleSeriesOnly;
      }
  
      /**
       * Sets the flag that controls whether or not the data bounds reported
       * by this renderer will exclude non-visible series and sends a
       * {@link RendererChangeEvent} to all registered listeners.
       *
       * @param visibleOnly  include only visible series.
       *
       * @since 1.0.13
       */
      public void setDataBoundsIncludesVisibleSeriesOnly(boolean visibleOnly) {
          this.dataBoundsIncludesVisibleSeriesOnly = visibleOnly;
          notifyListeners(new RendererChangeEvent(this, true));
      }
  
      /** The adjacent offset. */
      private static final double ADJ = Math.cos(Math.PI / 6.0);
  
      /** The opposite offset. */
      private static final double OPP = Math.sin(Math.PI / 6.0);
  
      /**
       * Calculates the item label anchor point.
       *
       * @param anchor  the anchor.
       * @param x  the x coordinate.
       * @param y  the y coordinate.
       * @param orientation  the plot orientation.
       *
       * @return The anchor point (never <code>null</code>).
       */
      protected Point2D calculateLabelAnchorPoint(ItemLabelAnchor anchor,
              double x, double y, PlotOrientation orientation) {
          Point2D result = null;
          if (anchor == ItemLabelAnchor.CENTER) {
              result = new Point2D.Double(x, y);
          }
          else if (anchor == ItemLabelAnchor.INSIDE1) {
              result = new Point2D.Double(x + OPP * this.itemLabelAnchorOffset,
                      y - ADJ * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.INSIDE2) {
              result = new Point2D.Double(x + ADJ * this.itemLabelAnchorOffset,
                      y - OPP * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.INSIDE3) {
              result = new Point2D.Double(x + this.itemLabelAnchorOffset, y);
          }
          else if (anchor == ItemLabelAnchor.INSIDE4) {
              result = new Point2D.Double(x + ADJ * this.itemLabelAnchorOffset,
                      y + OPP * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.INSIDE5) {
              result = new Point2D.Double(x + OPP * this.itemLabelAnchorOffset,
                      y + ADJ * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.INSIDE6) {
              result = new Point2D.Double(x, y + this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.INSIDE7) {
              result = new Point2D.Double(x - OPP * this.itemLabelAnchorOffset,
                      y + ADJ * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.INSIDE8) {
              result = new Point2D.Double(x - ADJ * this.itemLabelAnchorOffset,
                      y + OPP * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.INSIDE9) {
              result = new Point2D.Double(x - this.itemLabelAnchorOffset, y);
          }
          else if (anchor == ItemLabelAnchor.INSIDE10) {
              result = new Point2D.Double(x - ADJ * this.itemLabelAnchorOffset,
                      y - OPP * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.INSIDE11) {
              result = new Point2D.Double(x - OPP * this.itemLabelAnchorOffset,
                      y - ADJ * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.INSIDE12) {
              result = new Point2D.Double(x, y - this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE1) {
              result = new Point2D.Double(
                      x + 2.0 * OPP * this.itemLabelAnchorOffset,
                      y - 2.0 * ADJ * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE2) {
              result = new Point2D.Double(
                      x + 2.0 * ADJ * this.itemLabelAnchorOffset,
                      y - 2.0 * OPP * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE3) {
              result = new Point2D.Double(x + 2.0 * this.itemLabelAnchorOffset,
                      y);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE4) {
              result = new Point2D.Double(
                      x + 2.0 * ADJ * this.itemLabelAnchorOffset,
                      y + 2.0 * OPP * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE5) {
              result = new Point2D.Double(
                      x + 2.0 * OPP * this.itemLabelAnchorOffset,
                      y + 2.0 * ADJ * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE6) {
              result = new Point2D.Double(x,
                      y + 2.0 * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE7) {
              result = new Point2D.Double(
                      x - 2.0 * OPP * this.itemLabelAnchorOffset,
                      y + 2.0 * ADJ * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE8) {
              result = new Point2D.Double(
                      x - 2.0 * ADJ * this.itemLabelAnchorOffset,
                      y + 2.0 * OPP * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE9) {
              result = new Point2D.Double(x - 2.0 * this.itemLabelAnchorOffset,
                      y);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE10) {
              result = new Point2D.Double(
                      x - 2.0 * ADJ * this.itemLabelAnchorOffset,
                      y - 2.0 * OPP * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE11) {
              result = new Point2D.Double(
                  x - 2.0 * OPP * this.itemLabelAnchorOffset,
                  y - 2.0 * ADJ * this.itemLabelAnchorOffset);
          }
          else if (anchor == ItemLabelAnchor.OUTSIDE12) {
              result = new Point2D.Double(x,
                      y - 2.0 * this.itemLabelAnchorOffset);
          }
          return result;
      }
  
      /**
       * Registers an object to receive notification of changes to the renderer.
       *
       * @param listener  the listener (<code>null</code> not permitted).
       *
       * @see #removeChangeListener(RendererChangeListener)
       */
      public void addChangeListener(RendererChangeListener listener) {
          ParamChecks.nullNotPermitted(listener, "listener");
          this.listenerList.add(RendererChangeListener.class, listener);
      }
  
      /**
       * Deregisters an object so that it no longer receives
       * notification of changes to the renderer.
       *
       * @param listener  the object (<code>null</code> not permitted).
       *
       * @see #addChangeListener(RendererChangeListener)
       */
      public void removeChangeListener(RendererChangeListener listener) {
          ParamChecks.nullNotPermitted(listener, "listener");
          this.listenerList.remove(RendererChangeListener.class, listener);
      }
  
      /**
       * Returns <code>true</code> if the specified object is registered with
       * the dataset as a listener.  Most applications won't need to call this
       * method, it exists mainly for use by unit testing code.
       *
       * @param listener  the listener.
       *
       * @return A boolean.
       */
      public boolean hasListener(EventListener listener) {
          List<Object> list = Arrays.asList(this.listenerList.getListenerList());
          return list.contains(listener);
      }
  
      /**
       * Sends a {@link RendererChangeEvent} to all registered listeners.
       *
       * @since 1.0.5
       */
      protected void fireChangeEvent() {
  
          // the commented out code would be better, but only if
          // RendererChangeEvent is immutable, which it isn't.  See if there is
          // a way to fix this...
  
          //if (this.event == null) {
          //    this.event = new RendererChangeEvent(this);
          //}
          //notifyListeners(this.event);
  
          notifyListeners(new RendererChangeEvent(this));
      }
  
      /**
       * Notifies all registered listeners that the renderer has been modified.
       *
       * @param event  information about the change event.
       */
      public void notifyListeners(RendererChangeEvent event) {
          Object[] ls = this.listenerList.getListenerList();
          for (int i = ls.length - 2; i >= 0; i -= 2) {
              if (ls[i] == RendererChangeListener.class) {
                  ((RendererChangeListener) ls[i + 1]).rendererChanged(event);
              }
          }
      }
  
      /**
       * Tests this renderer for equality with another object.
       *
       * @param obj  the object (<code>null</code> permitted).
       *
       * @return <code>true</code> or <code>false</code>.
       */
      @Override
      public boolean equals(Object obj) {
          if (obj == this) {
              return true;
          }
          if (!(obj instanceof AbstractRenderer)) {
              return false;
          }
          AbstractRenderer that = (AbstractRenderer) obj;
          if (this.dataBoundsIncludesVisibleSeriesOnly
                  != that.dataBoundsIncludesVisibleSeriesOnly) {
              return false;
          }
          if (this.treatLegendShapeAsLine != that.treatLegendShapeAsLine) {
              return false;
          }
          if (this.defaultEntityRadius != that.defaultEntityRadius) {
              return false;
          }
          if (!this.seriesVisibleList.equals(that.seriesVisibleList)) {
              return false;
          }
          if (this.defaultSeriesVisible != that.defaultSeriesVisible) {
              return false;
          }
          if (!this.seriesVisibleInLegendList.equals(
                  that.seriesVisibleInLegendList)) {
              return false;
          }
          if (this.defaultSeriesVisibleInLegend
                  != that.defaultSeriesVisibleInLegend) {
              return false;
          }
          if (!ObjectUtilities.equal(this.paintList, that.paintList)) {
              return false;
          }
          if (!PaintUtilities.equal(this.defaultPaint, that.defaultPaint)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.fillPaintList, that.fillPaintList)) {
              return false;
          }
          if (!PaintUtilities.equal(this.defaultFillPaint,
                  that.defaultFillPaint)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.outlinePaintList,
                  that.outlinePaintList)) {
              return false;
          }
          if (!PaintUtilities.equal(this.defaultOutlinePaint,
                  that.defaultOutlinePaint)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.strokeList, that.strokeList)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.defaultStroke, that.defaultStroke)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.outlineStrokeList,
                  that.outlineStrokeList)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.defaultOutlineStroke,
                  that.defaultOutlineStroke)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.shapeList, that.shapeList)) {
              return false;
          }
          if (!ShapeUtilities.equal(this.defaultShape, that.defaultShape)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.itemLabelsVisibleList,
                  that.itemLabelsVisibleList)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.defaultItemLabelsVisible,
                  that.defaultItemLabelsVisible)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.itemLabelFontList,
                  that.itemLabelFontList)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.defaultItemLabelFont,
                  that.defaultItemLabelFont)) {
              return false;
          }
  
          if (!ObjectUtilities.equal(this.itemLabelPaintList,
                  that.itemLabelPaintList)) {
              return false;
          }
          if (!PaintUtilities.equal(this.defaultItemLabelPaint,
                  that.defaultItemLabelPaint)) {
              return false;
          }
  
          if (!ObjectUtilities.equal(this.positiveItemLabelPositionList,
                  that.positiveItemLabelPositionList)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.defaultPositiveItemLabelPosition,
                  that.defaultPositiveItemLabelPosition)) {
              return false;
          }
  
          if (!ObjectUtilities.equal(this.negativeItemLabelPositionList,
                  that.negativeItemLabelPositionList)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.defaultNegativeItemLabelPosition,
                  that.defaultNegativeItemLabelPosition)) {
              return false;
          }
          if (this.itemLabelAnchorOffset != that.itemLabelAnchorOffset) {
              return false;
          }
          if (!ObjectUtilities.equal(this.createEntitiesList,
                  that.createEntitiesList)) {
              return false;
          }
          if (this.defaultCreateEntities != that.defaultCreateEntities) {
              return false;
          }
          if (!ObjectUtilities.equal(this.legendShapeList,
                  that.legendShapeList)) {
              return false;
          }
          if (!ShapeUtilities.equal(this.defaultLegendShape,
                  that.defaultLegendShape)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.legendTextFont, that.legendTextFont)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.defaultLegendTextFont,
                  that.defaultLegendTextFont)) {
              return false;
          }
          if (!ObjectUtilities.equal(this.legendTextPaint,
                  that.legendTextPaint)) {
              return false;
          }
          if (!PaintUtilities.equal(this.defaultLegendTextPaint,
                  that.defaultLegendTextPaint)) {
              return false;
          }
          return true;
      }
  
      /**
       * Returns a hashcode for the renderer.
       *
       * @return The hashcode.
       */
      @Override
      public int hashCode() {
          int result = 193;
          result = HashUtilities.hashCode(result, this.seriesVisibleList);
          result = HashUtilities.hashCode(result, this.defaultSeriesVisible);
          result = HashUtilities.hashCode(result, this.seriesVisibleInLegendList);
          result = HashUtilities.hashCode(result, this.defaultSeriesVisibleInLegend);
          result = HashUtilities.hashCode(result, this.paintList);
          result = HashUtilities.hashCode(result, this.defaultPaint);
          result = HashUtilities.hashCode(result, this.fillPaintList);
          result = HashUtilities.hashCode(result, this.defaultFillPaint);
          result = HashUtilities.hashCode(result, this.outlinePaintList);
          result = HashUtilities.hashCode(result, this.defaultOutlinePaint);
          result = HashUtilities.hashCode(result, this.strokeList);
          result = HashUtilities.hashCode(result, this.defaultStroke);
          result = HashUtilities.hashCode(result, this.outlineStrokeList);
          result = HashUtilities.hashCode(result, this.defaultOutlineStroke);
          // shapeList
          // baseShape
          result = HashUtilities.hashCode(result, this.itemLabelsVisibleList);
          result = HashUtilities.hashCode(result, this.defaultItemLabelsVisible);
          // itemLabelFontList
          // baseItemLabelFont
          // itemLabelPaintList
          // baseItemLabelPaint
          // positiveItemLabelPositionList
          // basePositiveItemLabelPosition
          // negativeItemLabelPositionList
          // baseNegativeItemLabelPosition
          // itemLabelAnchorOffset
          // createEntityList
          // baseCreateEntities
          return result;
      }
  
      /**
       * Returns an independent copy of the renderer.
       *
       * @return A clone.
       *
       * @throws CloneNotSupportedException if some component of the renderer
       *         does not support cloning.
       */
      @Override
      protected Object clone() throws CloneNotSupportedException {
          AbstractRenderer clone = (AbstractRenderer) super.clone();
  
          if (this.seriesVisibleList != null) {
              clone.seriesVisibleList
                      = (BooleanList) this.seriesVisibleList.clone();
          }
  
          if (this.seriesVisibleInLegendList != null) {
              clone.seriesVisibleInLegendList
                      = (BooleanList) this.seriesVisibleInLegendList.clone();
          }
  
          // 'paint' : immutable, no need to clone reference
          if (this.paintList != null) {
              clone.paintList = (PaintList) this.paintList.clone();
          }
          // 'basePaint' : immutable, no need to clone reference
  
          if (this.fillPaintList != null) {
              clone.fillPaintList = (PaintList) this.fillPaintList.clone();
          }
          // 'outlinePaint' : immutable, no need to clone reference
          if (this.outlinePaintList != null) {
              clone.outlinePaintList = (PaintList) this.outlinePaintList.clone();
          }
          // 'baseOutlinePaint' : immutable, no need to clone reference
  
          // 'stroke' : immutable, no need to clone reference
          if (this.strokeList != null) {
              clone.strokeList = (StrokeList) this.strokeList.clone();
          }
          // 'baseStroke' : immutable, no need to clone reference
  
          // 'outlineStroke' : immutable, no need to clone reference
          if (this.outlineStrokeList != null) {
              clone.outlineStrokeList
                  = (StrokeList) this.outlineStrokeList.clone();
          }
          // 'baseOutlineStroke' : immutable, no need to clone reference
  
          if (this.shapeList != null) {
              clone.shapeList = (ShapeList) this.shapeList.clone();
          }
          if (this.defaultShape != null) {
              clone.defaultShape = ShapeUtilities.clone(this.defaultShape);
          }
  
          // 'itemLabelsVisible' : immutable, no need to clone reference
          if (this.itemLabelsVisibleList != null) {
              clone.itemLabelsVisibleList
                  = (BooleanList) this.itemLabelsVisibleList.clone();
          }
          // 'basePaint' : immutable, no need to clone reference
  
          // 'itemLabelFont' : immutable, no need to clone reference
          if (this.itemLabelFontList != null) {
              clone.itemLabelFontList
                  = (ObjectList<Font>) this.itemLabelFontList.clone();
          }
          // 'baseItemLabelFont' : immutable, no need to clone reference
  
          // 'itemLabelPaint' : immutable, no need to clone reference
          if (this.itemLabelPaintList != null) {
              clone.itemLabelPaintList
                  = (PaintList) this.itemLabelPaintList.clone();
          }
          // 'baseItemLabelPaint' : immutable, no need to clone reference
  
          // 'postiveItemLabelAnchor' : immutable, no need to clone reference
          if (this.positiveItemLabelPositionList != null) {
              clone.positiveItemLabelPositionList
                  = (ObjectList<ItemLabelPosition>) this.positiveItemLabelPositionList.clone();
          }
          // 'baseItemLabelAnchor' : immutable, no need to clone reference
  
          // 'negativeItemLabelAnchor' : immutable, no need to clone reference
          if (this.negativeItemLabelPositionList != null) {
              clone.negativeItemLabelPositionList
                  = (ObjectList<ItemLabelPosition>) this.negativeItemLabelPositionList.clone();
          }
          // 'baseNegativeItemLabelAnchor' : immutable, no need to clone reference
  
          if (this.createEntitiesList != null) {
              clone.createEntitiesList
                      = (BooleanList) this.createEntitiesList.clone();
          }
  
          if (this.legendShapeList != null) {
              clone.legendShapeList = (ShapeList) this.legendShapeList.clone();
          }
          if (this.legendTextFont != null) {
              clone.legendTextFont = (ObjectList<Font>) this.legendTextFont.clone();
          }
          if (this.legendTextPaint != null) {
              clone.legendTextPaint = (PaintList) this.legendTextPaint.clone();
          }
          clone.listenerList = new EventListenerList();
          clone.event = null;
          return clone;
      }
  
      /**
       * Provides serialization support.
       *
       * @param stream  the output stream.
       *
       * @throws IOException  if there is an I/O error.
       */
      private void writeObject(ObjectOutputStream stream) throws IOException {
          stream.defaultWriteObject();
          SerialUtilities.writePaint(this.defaultPaint, stream);
          SerialUtilities.writePaint(this.defaultFillPaint, stream);
          SerialUtilities.writePaint(this.defaultOutlinePaint, stream);
          SerialUtilities.writeStroke(this.defaultStroke, stream);
          SerialUtilities.writeStroke(this.defaultOutlineStroke, stream);
          SerialUtilities.writeShape(this.defaultShape, stream);
          SerialUtilities.writePaint(this.defaultItemLabelPaint, stream);
          SerialUtilities.writeShape(this.defaultLegendShape, stream);
          SerialUtilities.writePaint(this.defaultLegendTextPaint, stream);
      }
  
      /**
       * Provides serialization support.
       *
       * @param stream  the input stream.
       *
       * @throws IOException  if there is an I/O error.
       * @throws ClassNotFoundException  if there is a classpath problem.
       */
      private void readObject(ObjectInputStream stream)
              throws IOException, ClassNotFoundException {
          stream.defaultReadObject();
          this.defaultPaint = SerialUtilities.readPaint(stream);
          this.defaultFillPaint = SerialUtilities.readPaint(stream);
          this.defaultOutlinePaint = SerialUtilities.readPaint(stream);
          this.defaultStroke = SerialUtilities.readStroke(stream);
          this.defaultOutlineStroke = SerialUtilities.readStroke(stream);
          this.defaultShape = SerialUtilities.readShape(stream);
          this.defaultItemLabelPaint = SerialUtilities.readPaint(stream);
          this.defaultLegendShape = SerialUtilities.readShape(stream);
          this.defaultLegendTextPaint = SerialUtilities.readPaint(stream);
  
          // listeners are not restored automatically, but storage must be
          // provided...
          this.listenerList = new EventListenerList();
      }
  
  }
  