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