001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006 *
007 * Project Info: http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022 * USA.
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * ------------
028 * PiePlot.java
029 * ------------
030 * (C) Copyright 2000-2007, by Andrzej Porebski and Contributors.
031 *
032 * Original Author: Andrzej Porebski;
033 * Contributor(s): David Gilbert (for Object Refinery Limited);
034 * Martin Cordova (percentages in labels);
035 * Richard Atkinson (URL support for image maps);
036 * Christian W. Zuckschwerdt;
037 * Arnaud Lelievre;
038 * Andreas Schroeder (very minor);
039 *
040 * $Id: PiePlot.java,v 1.17.2.25 2007/06/14 15:04:21 mungady Exp $
041 *
042 * Changes (from 21-Jun-2001)
043 * --------------------------
044 * 21-Jun-2001 : Removed redundant JFreeChart parameter from constructors (DG);
045 * 18-Sep-2001 : Updated header (DG);
046 * 15-Oct-2001 : Data source classes moved to com.jrefinery.data.* (DG);
047 * 19-Oct-2001 : Moved series paint and stroke methods from JFreeChart.java to
048 * Plot.java (DG);
049 * 22-Oct-2001 : Renamed DataSource.java --> Dataset.java etc. (DG);
050 * 13-Nov-2001 : Modified plot subclasses so that null axes are possible for
051 * pie plot (DG);
052 * 17-Nov-2001 : Added PieDataset interface and amended this class accordingly,
053 * and completed removal of BlankAxis class as it is no longer
054 * required (DG);
055 * 19-Nov-2001 : Changed 'drawCircle' property to 'circular' property (DG);
056 * 21-Nov-2001 : Added options for exploding pie sections and filled out range
057 * of properties (DG);
058 * Added option for percentages in chart labels, based on code
059 * by Martin Cordova (DG);
060 * 30-Nov-2001 : Changed default font from "Arial" --> "SansSerif" (DG);
061 * 12-Dec-2001 : Removed unnecessary 'throws' clause in constructor (DG);
062 * 13-Dec-2001 : Added tooltips (DG);
063 * 16-Jan-2002 : Renamed tooltips class (DG);
064 * 22-Jan-2002 : Fixed bug correlating legend labels with pie data (DG);
065 * 05-Feb-2002 : Added alpha-transparency to plot class, and updated
066 * constructors accordingly (DG);
067 * 06-Feb-2002 : Added optional background image and alpha-transparency to Plot
068 * and subclasses. Clipped drawing within plot area (DG);
069 * 26-Mar-2002 : Added an empty zoom method (DG);
070 * 18-Apr-2002 : PieDataset is no longer sorted (oldman);
071 * 23-Apr-2002 : Moved dataset from JFreeChart to Plot. Added
072 * getLegendItemLabels() method (DG);
073 * 19-Jun-2002 : Added attributes to control starting angle and direction
074 * (default is now clockwise) (DG);
075 * 25-Jun-2002 : Removed redundant imports (DG);
076 * 02-Jul-2002 : Fixed sign of percentage bug introduced in 0.9.2 (DG);
077 * 16-Jul-2002 : Added check for null dataset in getLegendItemLabels() (DG);
078 * 30-Jul-2002 : Moved summation code to DatasetUtilities (DG);
079 * 05-Aug-2002 : Added URL support for image maps - new member variable for
080 * urlGenerator, modified constructor and minor change to the
081 * draw method (RA);
082 * 18-Sep-2002 : Modified the percent label creation and added setters for the
083 * formatters (AS);
084 * 24-Sep-2002 : Added getLegendItems() method (DG);
085 * 02-Oct-2002 : Fixed errors reported by Checkstyle (DG);
086 * 09-Oct-2002 : Added check for null entity collection (DG);
087 * 30-Oct-2002 : Changed PieDataset interface (DG);
088 * 18-Nov-2002 : Changed CategoryDataset to TableDataset (DG);
089 * 02-Jan-2003 : Fixed "no data" message (DG);
090 * 23-Jan-2003 : Modified to extract data from rows OR columns in
091 * CategoryDataset (DG);
092 * 14-Feb-2003 : Fixed label drawing so that foreground alpha does not apply
093 * (bug id 685536) (DG);
094 * 07-Mar-2003 : Modified to pass pieIndex on to PieSectionEntity and tooltip
095 * and URL generators (DG);
096 * 21-Mar-2003 : Added a minimum angle for drawing arcs
097 * (see bug id 620031) (DG);
098 * 24-Apr-2003 : Switched around PieDataset and KeyedValuesDataset (DG);
099 * 02-Jun-2003 : Fixed bug 721733 (DG);
100 * 30-Jul-2003 : Modified entity constructor (CZ);
101 * 19-Aug-2003 : Implemented Cloneable (DG);
102 * 29-Aug-2003 : Fixed bug 796936 (null pointer on setOutlinePaint()) (DG);
103 * 08-Sep-2003 : Added internationalization via use of properties
104 * resourceBundle (RFE 690236) (AL);
105 * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
106 * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
107 * 05-Nov-2003 : Fixed missing legend bug (DG);
108 * 10-Nov-2003 : Re-added the DatasetChangeListener to constructors (CZ);
109 * 29-Jan-2004 : Fixed clipping bug in draw() method (DG);
110 * 11-Mar-2004 : Major overhaul to improve labelling (DG);
111 * 31-Mar-2004 : Made an adjustment for the plot area when the label generator
112 * is null. Fixed null pointer exception when the label
113 * generator returns null for a label (DG);
114 * 06-Apr-2004 : Added getter, setter, serialization and draw support for
115 * labelBackgroundPaint (AS);
116 * 08-Apr-2004 : Added flag to control whether null values are ignored or
117 * not (DG);
118 * 15-Apr-2004 : Fixed some minor warnings from Eclipse (DG);
119 * 26-Apr-2004 : Added attributes for label outline and shadow (DG);
120 * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
121 * 04-Nov-2004 : Fixed null pointer exception with new LegendTitle class (DG);
122 * 09-Nov-2004 : Added user definable legend item shape (DG);
123 * 25-Nov-2004 : Added new legend label generator (DG);
124 * 20-Apr-2005 : Added a tool tip generator for legend labels (DG);
125 * 26-Apr-2005 : Removed LOGGER (DG);
126 * 05-May-2005 : Updated draw() method parameters (DG);
127 * 10-May-2005 : Added flag to control visibility of label linking lines, plus
128 * another flag to control the handling of zero values (DG);
129 * 08-Jun-2005 : Fixed bug in getLegendItems() method (not respecting flags
130 * for ignoring null and zero values), and fixed equals() method
131 * to handle GradientPaint (DG);
132 * 15-Jul-2005 : Added sectionOutlinesVisible attribute (DG);
133 * ------------- JFREECHART 1.0.x ---------------------------------------------
134 * 09-Jan-2006 : Fixed bug 1400442, inconsistent treatment of null and zero
135 * values in dataset (DG);
136 * 28-Feb-2006 : Fixed bug 1440415, bad distribution of pie section
137 * labels (DG);
138 * 27-Sep-2006 : Initialised baseSectionPaint correctly, added lookup methods
139 * for section paint, outline paint and outline stroke (DG);
140 * 27-Sep-2006 : Refactored paint and stroke methods to use keys rather than
141 * section indices (DG);
142 * 03-Oct-2006 : Replaced call to JRE 1.5 method (DG);
143 * 23-Nov-2006 : Added support for URLs for the legend items (DG);
144 * 24-Nov-2006 : Cloning fixes (DG);
145 * 17-Apr-2007 : Check for null label in legend items (DG);
146 * 19-Apr-2007 : Deprecated override settings (DG);
147 * 18-May-2007 : Set dataset for LegendItem (DG);
148 * 14-Jun-2007 : Added label distributor attribute (DG);
149 *
150 */
151
152 package org.jfree.chart.plot;
153
154 import java.awt.AlphaComposite;
155 import java.awt.BasicStroke;
156 import java.awt.Color;
157 import java.awt.Composite;
158 import java.awt.Font;
159 import java.awt.Graphics2D;
160 import java.awt.Paint;
161 import java.awt.Shape;
162 import java.awt.Stroke;
163 import java.awt.geom.Arc2D;
164 import java.awt.geom.Line2D;
165 import java.awt.geom.Point2D;
166 import java.awt.geom.Rectangle2D;
167 import java.io.IOException;
168 import java.io.ObjectInputStream;
169 import java.io.ObjectOutputStream;
170 import java.io.Serializable;
171 import java.util.Iterator;
172 import java.util.List;
173 import java.util.Map;
174 import java.util.ResourceBundle;
175 import java.util.TreeMap;
176
177 import org.jfree.chart.LegendItem;
178 import org.jfree.chart.LegendItemCollection;
179 import org.jfree.chart.PaintMap;
180 import org.jfree.chart.StrokeMap;
181 import org.jfree.chart.entity.EntityCollection;
182 import org.jfree.chart.entity.PieSectionEntity;
183 import org.jfree.chart.event.PlotChangeEvent;
184 import org.jfree.chart.labels.PieSectionLabelGenerator;
185 import org.jfree.chart.labels.PieToolTipGenerator;
186 import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
187 import org.jfree.chart.urls.PieURLGenerator;
188 import org.jfree.data.DefaultKeyedValues;
189 import org.jfree.data.KeyedValues;
190 import org.jfree.data.general.DatasetChangeEvent;
191 import org.jfree.data.general.DatasetUtilities;
192 import org.jfree.data.general.PieDataset;
193 import org.jfree.io.SerialUtilities;
194 import org.jfree.text.G2TextMeasurer;
195 import org.jfree.text.TextBlock;
196 import org.jfree.text.TextBox;
197 import org.jfree.text.TextUtilities;
198 import org.jfree.ui.RectangleAnchor;
199 import org.jfree.ui.RectangleInsets;
200 import org.jfree.util.ObjectUtilities;
201 import org.jfree.util.PaintUtilities;
202 import org.jfree.util.PublicCloneable;
203 import org.jfree.util.Rotation;
204 import org.jfree.util.ShapeUtilities;
205
206 /**
207 * A plot that displays data in the form of a pie chart, using data from any
208 * class that implements the {@link PieDataset} interface.
209 * <P>
210 * Special notes:
211 * <ol>
212 * <li>the default starting point is 12 o'clock and the pie sections proceed
213 * in a clockwise direction, but these settings can be changed;</li>
214 * <li>negative values in the dataset are ignored;</li>
215 * <li>there are utility methods for creating a {@link PieDataset} from a
216 * {@link org.jfree.data.category.CategoryDataset};</li>
217 * </ol>
218 *
219 * @see Plot
220 * @see PieDataset
221 */
222 public class PiePlot extends Plot implements Cloneable, Serializable {
223
224 /** For serialization. */
225 private static final long serialVersionUID = -795612466005590431L;
226
227 /** The default interior gap. */
228 public static final double DEFAULT_INTERIOR_GAP = 0.25;
229
230 /** The maximum interior gap (currently 40%). */
231 public static final double MAX_INTERIOR_GAP = 0.40;
232
233 /** The default starting angle for the pie chart. */
234 public static final double DEFAULT_START_ANGLE = 90.0;
235
236 /** The default section label font. */
237 public static final Font DEFAULT_LABEL_FONT = new Font("SansSerif",
238 Font.PLAIN, 10);
239
240 /** The default section label paint. */
241 public static final Paint DEFAULT_LABEL_PAINT = Color.black;
242
243 /** The default section label background paint. */
244 public static final Paint DEFAULT_LABEL_BACKGROUND_PAINT = new Color(255,
245 255, 192);
246
247 /** The default section label outline paint. */
248 public static final Paint DEFAULT_LABEL_OUTLINE_PAINT = Color.black;
249
250 /** The default section label outline stroke. */
251 public static final Stroke DEFAULT_LABEL_OUTLINE_STROKE = new BasicStroke(
252 0.5f);
253
254 /** The default section label shadow paint. */
255 public static final Paint DEFAULT_LABEL_SHADOW_PAINT = Color.lightGray;
256
257 /** The default minimum arc angle to draw. */
258 public static final double DEFAULT_MINIMUM_ARC_ANGLE_TO_DRAW = 0.00001;
259
260 /** The dataset for the pie chart. */
261 private PieDataset dataset;
262
263 /** The pie index (used by the {@link MultiplePiePlot} class). */
264 private int pieIndex;
265
266 /**
267 * The amount of space left around the outside of the pie plot, expressed
268 * as a percentage.
269 */
270 private double interiorGap;
271
272 /** Flag determining whether to draw an ellipse or a perfect circle. */
273 private boolean circular;
274
275 /** The starting angle. */
276 private double startAngle;
277
278 /** The direction for the pie segments. */
279 private Rotation direction;
280
281 /**
282 * The paint for ALL sections (overrides list).
283 *
284 * @deprecated This field is redundant, it is sufficient to use
285 * sectionPaintMap and baseSectionPaint. Deprecated as of version
286 * 1.0.6.
287 */
288 private transient Paint sectionPaint;
289
290 /** The section paint map. */
291 private PaintMap sectionPaintMap;
292
293 /** The base section paint (fallback). */
294 private transient Paint baseSectionPaint;
295
296 /**
297 * A flag that controls whether or not an outline is drawn for each
298 * section in the plot.
299 */
300 private boolean sectionOutlinesVisible;
301
302 /**
303 * The outline paint for ALL sections (overrides list).
304 *
305 * @deprecated This field is redundant, it is sufficient to use
306 * sectionOutlinePaintMap and baseSectionOutlinePaint. Deprecated as
307 * of version 1.0.6.
308 */
309 private transient Paint sectionOutlinePaint;
310
311 /** The section outline paint map. */
312 private PaintMap sectionOutlinePaintMap;
313
314 /** The base section outline paint (fallback). */
315 private transient Paint baseSectionOutlinePaint;
316
317 /**
318 * The outline stroke for ALL sections (overrides list).
319 *
320 * @deprecated This field is redundant, it is sufficient to use
321 * sectionOutlineStrokeMap and baseSectionOutlineStroke. Deprecated as
322 * of version 1.0.6.
323 */
324 private transient Stroke sectionOutlineStroke;
325
326 /** The section outline stroke map. */
327 private StrokeMap sectionOutlineStrokeMap;
328
329 /** The base section outline stroke (fallback). */
330 private transient Stroke baseSectionOutlineStroke;
331
332 /** The shadow paint. */
333 private transient Paint shadowPaint = Color.gray;
334
335 /** The x-offset for the shadow effect. */
336 private double shadowXOffset = 4.0f;
337
338 /** The y-offset for the shadow effect. */
339 private double shadowYOffset = 4.0f;
340
341 /** The percentage amount to explode each pie section. */
342 private Map explodePercentages;
343
344 /** The section label generator. */
345 private PieSectionLabelGenerator labelGenerator;
346
347 /** The font used to display the section labels. */
348 private Font labelFont;
349
350 /** The color used to draw the section labels. */
351 private transient Paint labelPaint;
352
353 /** The color used to draw the background of the section labels. */
354 private transient Paint labelBackgroundPaint;
355
356 /**
357 * The paint used to draw the outline of the section labels
358 * (<code>null</code> permitted).
359 */
360 private transient Paint labelOutlinePaint;
361
362 /**
363 * The stroke used to draw the outline of the section labels
364 * (<code>null</code> permitted).
365 */
366 private transient Stroke labelOutlineStroke;
367
368 /**
369 * The paint used to draw the shadow for the section labels
370 * (<code>null</code> permitted).
371 */
372 private transient Paint labelShadowPaint;
373
374 /** The maximum label width as a percentage of the plot width. */
375 private double maximumLabelWidth = 0.20;
376
377 /**
378 * The gap between the labels and the plot as a percentage of the plot
379 * width.
380 */
381 private double labelGap = 0.05;
382
383 /** A flag that controls whether or not the label links are drawn. */
384 private boolean labelLinksVisible;
385
386 /** The link margin. */
387 private double labelLinkMargin = 0.05;
388
389 /** The paint used for the label linking lines. */
390 private transient Paint labelLinkPaint = Color.black;
391
392 /** The stroke used for the label linking lines. */
393 private transient Stroke labelLinkStroke = new BasicStroke(0.5f);
394
395 /**
396 * The pie section label distributor.
397 *
398 * @since 1.0.6
399 */
400 private AbstractPieLabelDistributor labelDistributor;
401
402 /** The tooltip generator. */
403 private PieToolTipGenerator toolTipGenerator;
404
405 /** The URL generator. */
406 private PieURLGenerator urlGenerator;
407
408 /** The legend label generator. */
409 private PieSectionLabelGenerator legendLabelGenerator;
410
411 /** A tool tip generator for the legend. */
412 private PieSectionLabelGenerator legendLabelToolTipGenerator;
413
414 /**
415 * A URL generator for the legend items (optional).
416 *
417 * @since 1.0.4.
418 */
419 private PieURLGenerator legendLabelURLGenerator;
420
421 /**
422 * A flag that controls whether <code>null</code> values are ignored.
423 */
424 private boolean ignoreNullValues;
425
426 /**
427 * A flag that controls whether zero values are ignored.
428 */
429 private boolean ignoreZeroValues;
430
431 /** The legend item shape. */
432 private transient Shape legendItemShape;
433
434 /**
435 * The smallest arc angle that will get drawn (this is to avoid a bug in
436 * various Java implementations that causes the JVM to crash). See this
437 * link for details:
438 *
439 * http://www.jfree.org/phpBB2/viewtopic.php?t=2707
440 *
441 * ...and this bug report in the Java Bug Parade:
442 *
443 * http://developer.java.sun.com/developer/bugParade/bugs/4836495.html
444 */
445 private double minimumArcAngleToDraw;
446
447 /** The resourceBundle for the localization. */
448 protected static ResourceBundle localizationResources =
449 ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle");
450
451 /**
452 * Creates a new plot. The dataset is initially set to <code>null</code>.
453 */
454 public PiePlot() {
455 this(null);
456 }
457
458 /**
459 * Creates a plot that will draw a pie chart for the specified dataset.
460 *
461 * @param dataset the dataset (<code>null</code> permitted).
462 */
463 public PiePlot(PieDataset dataset) {
464 super();
465 this.dataset = dataset;
466 if (dataset != null) {
467 dataset.addChangeListener(this);
468 }
469 this.pieIndex = 0;
470
471 this.interiorGap = DEFAULT_INTERIOR_GAP;
472 this.circular = true;
473 this.startAngle = DEFAULT_START_ANGLE;
474 this.direction = Rotation.CLOCKWISE;
475 this.minimumArcAngleToDraw = DEFAULT_MINIMUM_ARC_ANGLE_TO_DRAW;
476
477 this.sectionPaint = null;
478 this.sectionPaintMap = new PaintMap();
479 this.baseSectionPaint = Color.gray;
480
481 this.sectionOutlinesVisible = true;
482 this.sectionOutlinePaint = null;
483 this.sectionOutlinePaintMap = new PaintMap();
484 this.baseSectionOutlinePaint = DEFAULT_OUTLINE_PAINT;
485
486 this.sectionOutlineStroke = null;
487 this.sectionOutlineStrokeMap = new StrokeMap();
488 this.baseSectionOutlineStroke = DEFAULT_OUTLINE_STROKE;
489
490 this.explodePercentages = new TreeMap();
491
492 this.labelGenerator = new StandardPieSectionLabelGenerator();
493 this.labelFont = DEFAULT_LABEL_FONT;
494 this.labelPaint = DEFAULT_LABEL_PAINT;
495 this.labelBackgroundPaint = DEFAULT_LABEL_BACKGROUND_PAINT;
496 this.labelOutlinePaint = DEFAULT_LABEL_OUTLINE_PAINT;
497 this.labelOutlineStroke = DEFAULT_LABEL_OUTLINE_STROKE;
498 this.labelShadowPaint = DEFAULT_LABEL_SHADOW_PAINT;
499 this.labelLinksVisible = true;
500 this.labelDistributor = new PieLabelDistributor(0);
501
502 this.toolTipGenerator = null;
503 this.urlGenerator = null;
504 this.legendLabelGenerator = new StandardPieSectionLabelGenerator();
505 this.legendLabelToolTipGenerator = null;
506 this.legendLabelURLGenerator = null;
507 this.legendItemShape = Plot.DEFAULT_LEGEND_ITEM_CIRCLE;
508
509 this.ignoreNullValues = false;
510 this.ignoreZeroValues = false;
511 }
512
513 /**
514 * Returns the dataset.
515 *
516 * @return The dataset (possibly <code>null</code>).
517 *
518 * @see #setDataset(PieDataset)
519 */
520 public PieDataset getDataset() {
521 return this.dataset;
522 }
523
524 /**
525 * Sets the dataset and sends a {@link DatasetChangeEvent} to 'this'.
526 *
527 * @param dataset the dataset (<code>null</code> permitted).
528 *
529 * @see #getDataset()
530 */
531 public void setDataset(PieDataset dataset) {
532 // if there is an existing dataset, remove the plot from the list of
533 // change listeners...
534 PieDataset existing = this.dataset;
535 if (existing != null) {
536 existing.removeChangeListener(this);
537 }
538
539 // set the new dataset, and register the chart as a change listener...
540 this.dataset = dataset;
541 if (dataset != null) {
542 setDatasetGroup(dataset.getGroup());
543 dataset.addChangeListener(this);
544 }
545
546 // send a dataset change event to self...
547 DatasetChangeEvent event = new DatasetChangeEvent(this, dataset);
548 datasetChanged(event);
549 }
550
551 /**
552 * Returns the pie index (this is used by the {@link MultiplePiePlot} class
553 * to track subplots).
554 *
555 * @return The pie index.
556 *
557 * @see #setPieIndex(int)
558 */
559 public int getPieIndex() {
560 return this.pieIndex;
561 }
562
563 /**
564 * Sets the pie index (this is used by the {@link MultiplePiePlot} class to
565 * track subplots).
566 *
567 * @param index the index.
568 *
569 * @see #getPieIndex()
570 */
571 public void setPieIndex(int index) {
572 this.pieIndex = index;
573 }
574
575 /**
576 * Returns the start angle for the first pie section. This is measured in
577 * degrees starting from 3 o'clock and measuring anti-clockwise.
578 *
579 * @return The start angle.
580 *
581 * @see #setStartAngle(double)
582 */
583 public double getStartAngle() {
584 return this.startAngle;
585 }
586
587 /**
588 * Sets the starting angle and sends a {@link PlotChangeEvent} to all
589 * registered listeners. The initial default value is 90 degrees, which
590 * corresponds to 12 o'clock. A value of zero corresponds to 3 o'clock...
591 * this is the encoding used by Java's Arc2D class.
592 *
593 * @param angle the angle (in degrees).
594 *
595 * @see #getStartAngle()
596 */
597 public void setStartAngle(double angle) {
598 this.startAngle = angle;
599 notifyListeners(new PlotChangeEvent(this));
600 }
601
602 /**
603 * Returns the direction in which the pie sections are drawn (clockwise or
604 * anti-clockwise).
605 *
606 * @return The direction (never <code>null</code>).
607 *
608 * @see #setDirection(Rotation)
609 */
610 public Rotation getDirection() {
611 return this.direction;
612 }
613
614 /**
615 * Sets the direction in which the pie sections are drawn and sends a
616 * {@link PlotChangeEvent} to all registered listeners.
617 *
618 * @param direction the direction (<code>null</code> not permitted).
619 *
620 * @see #getDirection()
621 */
622 public void setDirection(Rotation direction) {
623 if (direction == null) {
624 throw new IllegalArgumentException("Null 'direction' argument.");
625 }
626 this.direction = direction;
627 notifyListeners(new PlotChangeEvent(this));
628
629 }
630
631 /**
632 * Returns the interior gap, measured as a percentage of the available
633 * drawing space.
634 *
635 * @return The gap (as a percentage of the available drawing space).
636 *
637 * @see #setInteriorGap(double)
638 */
639 public double getInteriorGap() {
640 return this.interiorGap;
641 }
642
643 /**
644 * Sets the interior gap and sends a {@link PlotChangeEvent} to all
645 * registered listeners. This controls the space between the edges of the
646 * pie plot and the plot area itself (the region where the section labels
647 * appear).
648 *
649 * @param percent the gap (as a percentage of the available drawing space).
650 *
651 * @see #getInteriorGap()
652 */
653 public void setInteriorGap(double percent) {
654
655 // check arguments...
656 if ((percent < 0.0) || (percent > MAX_INTERIOR_GAP)) {
657 throw new IllegalArgumentException(
658 "Invalid 'percent' (" + percent + ") argument.");
659 }
660
661 // make the change...
662 if (this.interiorGap != percent) {
663 this.interiorGap = percent;
664 notifyListeners(new PlotChangeEvent(this));
665 }
666
667 }
668
669 /**
670 * Returns a flag indicating whether the pie chart is circular, or
671 * stretched into an elliptical shape.
672 *
673 * @return A flag indicating whether the pie chart is circular.
674 *
675 * @see #setCircular(boolean)
676 */
677 public boolean isCircular() {
678 return this.circular;
679 }
680
681 /**
682 * A flag indicating whether the pie chart is circular, or stretched into
683 * an elliptical shape.
684 *
685 * @param flag the new value.
686 *
687 * @see #isCircular()
688 */
689 public void setCircular(boolean flag) {
690 setCircular(flag, true);
691 }
692
693 /**
694 * Sets the circular attribute and, if requested, sends a
695 * {@link PlotChangeEvent} to all registered listeners.
696 *
697 * @param circular the new value of the flag.
698 * @param notify notify listeners?
699 *
700 * @see #isCircular()
701 */
702 public void setCircular(boolean circular, boolean notify) {
703 this.circular = circular;
704 if (notify) {
705 notifyListeners(new PlotChangeEvent(this));
706 }
707 }
708
709 /**
710 * Returns the flag that controls whether <code>null</code> values in the
711 * dataset are ignored.
712 *
713 * @return A boolean.
714 *
715 * @see #setIgnoreNullValues(boolean)
716 */
717 public boolean getIgnoreNullValues() {
718 return this.ignoreNullValues;
719 }
720
721 /**
722 * Sets a flag that controls whether <code>null</code> values are ignored,
723 * and sends a {@link PlotChangeEvent} to all registered listeners. At
724 * present, this only affects whether or not the key is presented in the
725 * legend.
726 *
727 * @param flag the flag.
728 *
729 * @see #getIgnoreNullValues()
730 * @see #setIgnoreZeroValues(boolean)
731 */
732 public void setIgnoreNullValues(boolean flag) {
733 this.ignoreNullValues = flag;
734 notifyListeners(new PlotChangeEvent(this));
735 }
736
737 /**
738 * Returns the flag that controls whether zero values in the
739 * dataset are ignored.
740 *
741 * @return A boolean.
742 *
743 * @see #setIgnoreZeroValues(boolean)
744 */
745 public boolean getIgnoreZeroValues() {
746 return this.ignoreZeroValues;
747 }
748
749 /**
750 * Sets a flag that controls whether zero values are ignored,
751 * and sends a {@link PlotChangeEvent} to all registered listeners. This
752 * only affects whether or not a label appears for the non-visible
753 * pie section.
754 *
755 * @param flag the flag.
756 *
757 * @see #getIgnoreZeroValues()
758 * @see #setIgnoreNullValues(boolean)
759 */
760 public void setIgnoreZeroValues(boolean flag) {
761 this.ignoreZeroValues = flag;
762 notifyListeners(new PlotChangeEvent(this));
763 }
764
765 //// SECTION PAINT ////////////////////////////////////////////////////////
766
767 /**
768 * Returns the paint for the specified section. This is equivalent to
769 * <code>lookupSectionPaint(section, false)</code>.
770 *
771 * @param key the section key.
772 *
773 * @return The paint for the specified section.
774 *
775 * @since 1.0.3
776 *
777 * @see #lookupSectionPaint(Comparable, boolean)
778 */
779 protected Paint lookupSectionPaint(Comparable key) {
780 return lookupSectionPaint(key, false);
781 }
782
783 /**
784 * Returns the paint for the specified section. The lookup involves these
785 * steps:
786 * <ul>
787 * <li>if {@link #getSectionPaint()} is non-<code>null</code>, return
788 * it;</li>
789 * <li>if {@link #getSectionPaint(int)} is non-<code>null</code> return
790 * it;</li>
791 * <li>if {@link #getSectionPaint(int)} is <code>null</code> but
792 * <code>autoPopulate</code> is <code>true</code>, attempt to fetch
793 * a new paint from the drawing supplier
794 * ({@link #getDrawingSupplier()});
795 * <li>if all else fails, return {@link #getBaseSectionPaint()}.
796 * </ul>
797 *
798 * @param key the section key.
799 * @param autoPopulate a flag that controls whether the drawing supplier
800 * is used to auto-populate the section paint settings.
801 *
802 * @return The paint.
803 *
804 * @since 1.0.3
805 */
806 protected Paint lookupSectionPaint(Comparable key, boolean autoPopulate) {
807
808 // is there an override?
809 Paint result = getSectionPaint();
810 if (result != null) {
811 return result;
812 }
813
814 // if not, check if there is a paint defined for the specified key
815 result = this.sectionPaintMap.getPaint(key);
816 if (result != null) {
817 return result;
818 }
819
820 // nothing defined - do we autoPopulate?
821 if (autoPopulate) {
822 DrawingSupplier ds = getDrawingSupplier();
823 if (ds != null) {
824 result = ds.getNextPaint();
825 this.sectionPaintMap.put(key, result);
826 }
827 else {
828 result = this.baseSectionPaint;
829 }
830 }
831 else {
832 result = this.baseSectionPaint;
833 }
834 return result;
835 }
836
837 /**
838 * Returns the paint for ALL sections in the plot.
839 *
840 * @return The paint (possibly <code>null</code>).
841 *
842 * @see #setSectionPaint(Paint)
843 *
844 * @deprecated Use {@link #getSectionPaint(Comparable)} and
845 * {@link #getBaseSectionPaint()}. Deprecated as of version 1.0.6.
846 */
847 public Paint getSectionPaint() {
848 return this.sectionPaint;
849 }
850
851 /**
852 * Sets the paint for ALL sections in the plot. If this is set to
853 * </code>null</code>, then a list of paints is used instead (to allow
854 * different colors to be used for each section).
855 *
856 * @param paint the paint (<code>null</code> permitted).
857 *
858 * @see #getSectionPaint()
859 *
860 * @deprecated Use {@link #setSectionPaint(Comparable, Paint)} and
861 * {@link #setBaseSectionPaint(Paint)}. Deprecated as of version 1.0.6.
862 */
863 public void setSectionPaint(Paint paint) {
864 this.sectionPaint = paint;
865 notifyListeners(new PlotChangeEvent(this));
866 }
867
868 /**
869 * Returns a key for the specified section. If there is no such section
870 * in the dataset, we generate a key. This is to provide some backward
871 * compatibility for the (now deprecated) methods that get/set attributes
872 * based on section indices. The preferred way of doing this now is to
873 * link the attributes directly to the section key (there are new methods
874 * for this, starting from version 1.0.3).
875 *
876 * @param section the section index.
877 *
878 * @return The key.
879 *
880 * @since 1.0.3
881 */
882 protected Comparable getSectionKey(int section) {
883 Comparable key = null;
884 if (this.dataset != null) {
885 if (section >= 0 && section < this.dataset.getItemCount()) {
886 key = this.dataset.getKey(section);
887 }
888 }
889 if (key == null) {
890 key = new Integer(section);
891 }
892 return key;
893 }
894
895 /**
896 * Returns the paint associated with the specified key, or
897 * <code>null</code> if there is no paint associated with the key.
898 *
899 * @param key the key (<code>null</code> not permitted).
900 *
901 * @return The paint associated with the specified key, or
902 * <code>null</code>.
903 *
904 * @throws IllegalArgumentException if <code>key</code> is
905 * <code>null</code>.
906 *
907 * @see #setSectionPaint(Comparable, Paint)
908 *
909 * @since 1.0.3
910 */
911 public Paint getSectionPaint(Comparable key) {
912 // null argument check delegated...
913 return this.sectionPaintMap.getPaint(key);
914 }
915
916 /**
917 * Sets the paint associated with the specified key, and sends a
918 * {@link PlotChangeEvent} to all registered listeners.
919 *
920 * @param key the key (<code>null</code> not permitted).
921 * @param paint the paint.
922 *
923 * @throws IllegalArgumentException if <code>key</code> is
924 * <code>null</code>.
925 *
926 * @see #getSectionPaint(Comparable)
927 *
928 * @since 1.0.3
929 */
930 public void setSectionPaint(Comparable key, Paint paint) {
931 // null argument check delegated...
932 this.sectionPaintMap.put(key, paint);
933 notifyListeners(new PlotChangeEvent(this));
934 }
935
936 /**
937 * Returns the base section paint. This is used when no other paint is
938 * defined, which is rare. The default value is <code>Color.gray</code>.
939 *
940 * @return The paint (never <code>null</code>).
941 *
942 * @see #setBaseSectionPaint(Paint)
943 */
944 public Paint getBaseSectionPaint() {
945 return this.baseSectionPaint;
946 }
947
948 /**
949 * Sets the base section paint and sends a {@link PlotChangeEvent} to all
950 * registered listeners.
951 *
952 * @param paint the paint (<code>null</code> not permitted).
953 *
954 * @see #getBaseSectionPaint()
955 */
956 public void setBaseSectionPaint(Paint paint) {
957 if (paint == null) {
958 throw new IllegalArgumentException("Null 'paint' argument.");
959 }
960 this.baseSectionPaint = paint;
961 notifyListeners(new PlotChangeEvent(this));
962 }
963
964 //// SECTION OUTLINE PAINT ////////////////////////////////////////////////
965
966 /**
967 * Returns the flag that controls whether or not the outline is drawn for
968 * each pie section.
969 *
970 * @return The flag that controls whether or not the outline is drawn for
971 * each pie section.
972 *
973 * @see #setSectionOutlinesVisible(boolean)
974 */
975 public boolean getSectionOutlinesVisible() {
976 return this.sectionOutlinesVisible;
977 }
978
979 /**
980 * Sets the flag that controls whether or not the outline is drawn for
981 * each pie section, and sends a {@link PlotChangeEvent} to all registered
982 * listeners.
983 *
984 * @param visible the flag.
985 *
986 * @see #getSectionOutlinesVisible()
987 */
988 public void setSectionOutlinesVisible(boolean visible) {
989 this.sectionOutlinesVisible = visible;
990 notifyListeners(new PlotChangeEvent(this));
991 }
992
993 /**
994 * Returns the outline paint for the specified section. This is equivalent
995 * to <code>lookupSectionPaint(section, false)</code>.
996 *
997 * @param key the section key.
998 *
999 * @return The paint for the specified section.
1000 *
1001 * @since 1.0.3
1002 *
1003 * @see #lookupSectionOutlinePaint(Comparable, boolean)
1004 */
1005 protected Paint lookupSectionOutlinePaint(Comparable key) {
1006 return lookupSectionOutlinePaint(key, false);
1007 }
1008
1009 /**
1010 * Returns the outline paint for the specified section. The lookup
1011 * involves these steps:
1012 * <ul>
1013 * <li>if {@link #getSectionOutlinePaint()} is non-<code>null</code>,
1014 * return it;</li>
1015 * <li>otherwise, if {@link #getSectionOutlinePaint(int)} is
1016 * non-<code>null</code> return it;</li>
1017 * <li>if {@link #getSectionOutlinePaint(int)} is <code>null</code> but
1018 * <code>autoPopulate</code> is <code>true</code>, attempt to fetch
1019 * a new outline paint from the drawing supplier
1020 * ({@link #getDrawingSupplier()});
1021 * <li>if all else fails, return {@link #getBaseSectionOutlinePaint()}.
1022 * </ul>
1023 *
1024 * @param key the section key.
1025 * @param autoPopulate a flag that controls whether the drawing supplier
1026 * is used to auto-populate the section outline paint settings.
1027 *
1028 * @return The paint.
1029 *
1030 * @since 1.0.3
1031 */
1032 protected Paint lookupSectionOutlinePaint(Comparable key,
1033 boolean autoPopulate) {
1034
1035 // is there an override?
1036 Paint result = getSectionOutlinePaint();
1037 if (result != null) {
1038 return result;
1039 }
1040
1041 // if not, check if there is a paint defined for the specified key
1042 result = this.sectionOutlinePaintMap.getPaint(key);
1043 if (result != null) {
1044 return result;
1045 }
1046
1047 // nothing defined - do we autoPopulate?
1048 if (autoPopulate) {
1049 DrawingSupplier ds = getDrawingSupplier();
1050 if (ds != null) {
1051 result = ds.getNextOutlinePaint();
1052 this.sectionOutlinePaintMap.put(key, result);
1053 }
1054 else {
1055 result = this.baseSectionOutlinePaint;
1056 }
1057 }
1058 else {
1059 result = this.baseSectionOutlinePaint;
1060 }
1061 return result;
1062 }
1063
1064 /**
1065 * Returns the outline paint for ALL sections in the plot.
1066 *
1067 * @return The paint (possibly <code>null</code>).
1068 *
1069 * @see #setSectionOutlinePaint(Paint)
1070 *
1071 * @deprecated Use {@link #getSectionOutlinePaint(Comparable)} and
1072 * {@link #getBaseSectionOutlinePaint()}. Deprecated as of version
1073 * 1.0.6.
1074 */
1075 public Paint getSectionOutlinePaint() {
1076 return this.sectionOutlinePaint;
1077 }
1078
1079 /**
1080 * Sets the outline paint for ALL sections in the plot. If this is set to
1081 * </code>null</code>, then a list of paints is used instead (to allow
1082 * different colors to be used for each section).
1083 *
1084 * @param paint the paint (<code>null</code> permitted).
1085 *
1086 * @see #getSectionOutlinePaint()
1087 *
1088 * @deprecated Use {@link #setSectionOutlinePaint(Comparable, Paint)} and
1089 * {@link #setBaseSectionOutlinePaint(Paint)}. Deprecated as of
1090 * version 1.0.6.
1091 */
1092 public void setSectionOutlinePaint(Paint paint) {
1093 this.sectionOutlinePaint = paint;
1094 notifyListeners(new PlotChangeEvent(this));
1095 }
1096
1097 /**
1098 * Returns the outline paint associated with the specified key, or
1099 * <code>null</code> if there is no paint associated with the key.
1100 *
1101 * @param key the key (<code>null</code> not permitted).
1102 *
1103 * @return The paint associated with the specified key, or
1104 * <code>null</code>.
1105 *
1106 * @throws IllegalArgumentException if <code>key</code> is
1107 * <code>null</code>.
1108 *
1109 * @see #setSectionOutlinePaint(Comparable, Paint)
1110 *
1111 * @since 1.0.3
1112 */
1113 public Paint getSectionOutlinePaint(Comparable key) {
1114 // null argument check delegated...
1115 return this.sectionOutlinePaintMap.getPaint(key);
1116 }
1117
1118 /**
1119 * Sets the outline paint associated with the specified key, and sends a
1120 * {@link PlotChangeEvent} to all registered listeners.
1121 *
1122 * @param key the key (<code>null</code> not permitted).
1123 * @param paint the paint.
1124 *
1125 * @throws IllegalArgumentException if <code>key</code> is
1126 * <code>null</code>.
1127 *
1128 * @see #getSectionOutlinePaint(Comparable)
1129 *
1130 * @since 1.0.3
1131 */
1132 public void setSectionOutlinePaint(Comparable key, Paint paint) {
1133 // null argument check delegated...
1134 this.sectionOutlinePaintMap.put(key, paint);
1135 notifyListeners(new PlotChangeEvent(this));
1136 }
1137
1138 /**
1139 * Returns the base section paint. This is used when no other paint is
1140 * available.
1141 *
1142 * @return The paint (never <code>null</code>).
1143 *
1144 * @see #setBaseSectionOutlinePaint(Paint)
1145 */
1146 public Paint getBaseSectionOutlinePaint() {
1147 return this.baseSectionOutlinePaint;
1148 }
1149
1150 /**
1151 * Sets the base section paint.
1152 *
1153 * @param paint the paint (<code>null</code> not permitted).
1154 *
1155 * @see #getBaseSectionOutlinePaint()
1156 */
1157 public void setBaseSectionOutlinePaint(Paint paint) {
1158 if (paint == null) {
1159 throw new IllegalArgumentException("Null 'paint' argument.");
1160 }
1161 this.baseSectionOutlinePaint = paint;
1162 notifyListeners(new PlotChangeEvent(this));
1163 }
1164
1165 //// SECTION OUTLINE STROKE ///////////////////////////////////////////////
1166
1167 /**
1168 * Returns the outline stroke for the specified section. This is equivalent
1169 * to <code>lookupSectionOutlineStroke(section, false)</code>.
1170 *
1171 * @param key the section key.
1172 *
1173 * @return The stroke for the specified section.
1174 *
1175 * @since 1.0.3
1176 *
1177 * @see #lookupSectionOutlineStroke(Comparable, boolean)
1178 */
1179 protected Stroke lookupSectionOutlineStroke(Comparable key) {
1180 return lookupSectionOutlineStroke(key, false);
1181 }
1182
1183 /**
1184 * Returns the outline stroke for the specified section. The lookup
1185 * involves these steps:
1186 * <ul>
1187 * <li>if {@link #getSectionOutlineStroke()} is non-<code>null</code>,
1188 * return it;</li>
1189 * <li>otherwise, if {@link #getSectionOutlineStroke(int)} is
1190 * non-<code>null</code> return it;</li>
1191 * <li>if {@link #getSectionOutlineStroke(int)} is <code>null</code> but
1192 * <code>autoPopulate</code> is <code>true</code>, attempt to fetch
1193 * a new outline stroke from the drawing supplier
1194 * ({@link #getDrawingSupplier()});
1195 * <li>if all else fails, return {@link #getBaseSectionOutlineStroke()}.
1196 * </ul>
1197 *
1198 * @param key the section key.
1199 * @param autoPopulate a flag that controls whether the drawing supplier
1200 * is used to auto-populate the section outline stroke settings.
1201 *
1202 * @return The stroke.
1203 *
1204 * @since 1.0.3
1205 */
1206 protected Stroke lookupSectionOutlineStroke(Comparable key,
1207 boolean autoPopulate) {
1208
1209 // is there an override?
1210 Stroke result = getSectionOutlineStroke();
1211 if (result != null) {
1212 return result;
1213 }
1214
1215 // if not, check if there is a stroke defined for the specified key
1216 result = this.sectionOutlineStrokeMap.getStroke(key);
1217 if (result != null) {
1218 return result;
1219 }
1220
1221 // nothing defined - do we autoPopulate?
1222 if (autoPopulate) {
1223 DrawingSupplier ds = getDrawingSupplier();
1224 if (ds != null) {
1225 result = ds.getNextOutlineStroke();
1226 this.sectionOutlineStrokeMap.put(key, result);
1227 }
1228 else {
1229 result = this.baseSectionOutlineStroke;
1230 }
1231 }
1232 else {
1233 result = this.baseSectionOutlineStroke;
1234 }
1235 return result;
1236 }
1237
1238 /**
1239 * Returns the outline stroke for ALL sections in the plot.
1240 *
1241 * @return The stroke (possibly <code>null</code>).
1242 *
1243 * @see #setSectionOutlineStroke(Stroke)
1244 *
1245 * @deprecated Use {@link #getSectionOutlineStroke(Comparable)} and
1246 * {@link #getBaseSectionOutlineStroke()}. Deprecated as of version
1247 * 1.0.6.
1248 */
1249 public Stroke getSectionOutlineStroke() {
1250 return this.sectionOutlineStroke;
1251 }
1252
1253 /**
1254 * Sets the outline stroke for ALL sections in the plot. If this is set to
1255 * </code>null</code>, then a list of paints is used instead (to allow
1256 * different colors to be used for each section).
1257 *
1258 * @param stroke the stroke (<code>null</code> permitted).
1259 *
1260 * @see #getSectionOutlineStroke()
1261 *
1262 * @deprecated Use {@link #setSectionOutlineStroke(Comparable, Stroke)} and
1263 * {@link #setBaseSectionOutlineStroke(Stroke)}. Deprecated as of
1264 * version 1.0.6.
1265 */
1266 public void setSectionOutlineStroke(Stroke stroke) {
1267 this.sectionOutlineStroke = stroke;
1268 notifyListeners(new PlotChangeEvent(this));
1269 }
1270
1271 /**
1272 * Returns the outline stroke associated with the specified key, or
1273 * <code>null</code> if there is no stroke associated with the key.
1274 *
1275 * @param key the key (<code>null</code> not permitted).
1276 *
1277 * @return The stroke associated with the specified key, or
1278 * <code>null</code>.
1279 *
1280 * @throws IllegalArgumentException if <code>key</code> is
1281 * <code>null</code>.
1282 *
1283 * @see #setSectionOutlineStroke(Comparable, Stroke)
1284 *
1285 * @since 1.0.3
1286 */
1287 public Stroke getSectionOutlineStroke(Comparable key) {
1288 // null argument check delegated...
1289 return this.sectionOutlineStrokeMap.getStroke(key);
1290 }
1291
1292 /**
1293 * Sets the outline stroke associated with the specified key, and sends a
1294 * {@link PlotChangeEvent} to all registered listeners.
1295 *
1296 * @param key the key (<code>null</code> not permitted).
1297 * @param stroke the stroke.
1298 *
1299 * @throws IllegalArgumentException if <code>key</code> is
1300 * <code>null</code>.
1301 *
1302 * @see #getSectionOutlineStroke(Comparable)
1303 *
1304 * @since 1.0.3
1305 */
1306 public void setSectionOutlineStroke(Comparable key, Stroke stroke) {
1307 // null argument check delegated...
1308 this.sectionOutlineStrokeMap.put(key, stroke);
1309 notifyListeners(new PlotChangeEvent(this));
1310 }
1311
1312 /**
1313 * Returns the base section stroke. This is used when no other stroke is
1314 * available.
1315 *
1316 * @return The stroke (never <code>null</code>).
1317 *
1318 * @see #setBaseSectionOutlineStroke(Stroke)
1319 */
1320 public Stroke getBaseSectionOutlineStroke() {
1321 return this.baseSectionOutlineStroke;
1322 }
1323
1324 /**
1325 * Sets the base section stroke.
1326 *
1327 * @param stroke the stroke (<code>null</code> not permitted).
1328 *
1329 * @see #getBaseSectionOutlineStroke()
1330 */
1331 public void setBaseSectionOutlineStroke(Stroke stroke) {
1332 if (stroke == null) {
1333 throw new IllegalArgumentException("Null 'stroke' argument.");
1334 }
1335 this.baseSectionOutlineStroke = stroke;
1336 notifyListeners(new PlotChangeEvent(this));
1337 }
1338
1339 /**
1340 * Returns the shadow paint.
1341 *
1342 * @return The paint (possibly <code>null</code>).
1343 *
1344 * @see #setShadowPaint(Paint)
1345 */
1346 public Paint getShadowPaint() {
1347 return this.shadowPaint;
1348 }
1349
1350 /**
1351 * Sets the shadow paint and sends a {@link PlotChangeEvent} to all
1352 * registered listeners.
1353 *
1354 * @param paint the paint (<code>null</code> permitted).
1355 *
1356 * @see #getShadowPaint()
1357 */
1358 public void setShadowPaint(Paint paint) {
1359 this.shadowPaint = paint;
1360 notifyListeners(new PlotChangeEvent(this));
1361 }
1362
1363 /**
1364 * Returns the x-offset for the shadow effect.
1365 *
1366 * @return The offset (in Java2D units).
1367 *
1368 * @see #setShadowXOffset(double)
1369 */
1370 public double getShadowXOffset() {
1371 return this.shadowXOffset;
1372 }
1373
1374 /**
1375 * Sets the x-offset for the shadow effect and sends a
1376 * {@link PlotChangeEvent} to all registered listeners.
1377 *
1378 * @param offset the offset (in Java2D units).
1379 *
1380 * @see #getShadowXOffset()
1381 */
1382 public void setShadowXOffset(double offset) {
1383 this.shadowXOffset = offset;
1384 notifyListeners(new PlotChangeEvent(this));
1385 }
1386
1387 /**
1388 * Returns the y-offset for the shadow effect.
1389 *
1390 * @return The offset (in Java2D units).
1391 *
1392 * @see #setShadowYOffset(double)
1393 */
1394 public double getShadowYOffset() {
1395 return this.shadowYOffset;
1396 }
1397
1398 /**
1399 * Sets the y-offset for the shadow effect and sends a
1400 * {@link PlotChangeEvent} to all registered listeners.
1401 *
1402 * @param offset the offset (in Java2D units).
1403 *
1404 * @see #getShadowYOffset()
1405 */
1406 public void setShadowYOffset(double offset) {
1407 this.shadowYOffset = offset;
1408 notifyListeners(new PlotChangeEvent(this));
1409 }
1410
1411 /**
1412 * Returns the amount that the section with the specified key should be
1413 * exploded.
1414 *
1415