Source for org.jfree.chart.renderer.AbstractRenderer

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