001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2011, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [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 * Plot.java 029 * --------- 030 * (C) Copyright 2000-2011, by Object Refinery Limited and Contributors. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): Sylvain Vieujot; 034 * Jeremy Bowman; 035 * Andreas Schneider; 036 * Gideon Krause; 037 * Nicolas Brodu; 038 * Michal Krause; 039 * Richard West, Advanced Micro Devices, Inc.; 040 * Peter Kolb - patches 2603321, 2809117; 041 * 042 * Changes 043 * ------- 044 * 21-Jun-2001 : Removed redundant JFreeChart parameter from constructors (DG); 045 * 18-Sep-2001 : Updated header info and fixed DOS encoding problem (DG); 046 * 19-Oct-2001 : Moved series paint and stroke methods from JFreeChart 047 * class (DG); 048 * 23-Oct-2001 : Created renderer for LinePlot class (DG); 049 * 07-Nov-2001 : Changed type names for ChartChangeEvent (DG); 050 * Tidied up some Javadoc comments (DG); 051 * 13-Nov-2001 : Changes to allow for null axes on plots such as PiePlot (DG); 052 * Added plot/axis compatibility checks (DG); 053 * 12-Dec-2001 : Changed constructors to protected, and removed unnecessary 054 * 'throws' clauses (DG); 055 * 13-Dec-2001 : Added tooltips (DG); 056 * 22-Jan-2002 : Added handleClick() method, as part of implementation for 057 * crosshairs (DG); 058 * Moved tooltips reference into ChartInfo class (DG); 059 * 23-Jan-2002 : Added test for null axes in chartChanged() method, thanks 060 * to Barry Evans for the bug report (number 506979 on 061 * SourceForge) (DG); 062 * Added a zoom() method (DG); 063 * 05-Feb-2002 : Updated setBackgroundPaint(), setOutlineStroke() and 064 * setOutlinePaint() to better handle null values, as suggested 065 * by Sylvain Vieujot (DG); 066 * 06-Feb-2002 : Added background image, plus alpha transparency for background 067 * and foreground (DG); 068 * 06-Mar-2002 : Added AxisConstants interface (DG); 069 * 26-Mar-2002 : Changed zoom method from empty to abstract (DG); 070 * 23-Apr-2002 : Moved dataset from JFreeChart class (DG); 071 * 11-May-2002 : Added ShapeFactory interface for getShape() methods, 072 * contributed by Jeremy Bowman (DG); 073 * 28-May-2002 : Fixed bug in setSeriesPaint(int, Paint) for subplots (AS); 074 * 25-Jun-2002 : Removed redundant imports (DG); 075 * 30-Jul-2002 : Added 'no data' message for charts with null or empty 076 * datasets (DG); 077 * 21-Aug-2002 : Added code to extend series array if necessary (refer to 078 * SourceForge bug id 594547 for details) (DG); 079 * 17-Sep-2002 : Fixed bug in getSeriesOutlineStroke() method, reported by 080 * Andreas Schroeder (DG); 081 * 23-Sep-2002 : Added getLegendItems() abstract method (DG); 082 * 24-Sep-2002 : Removed firstSeriesIndex, subplots now use their own paint 083 * settings, there is a new mechanism for the legend to collect 084 * the legend items (DG); 085 * 27-Sep-2002 : Added dataset group (DG); 086 * 14-Oct-2002 : Moved listener storage into EventListenerList. Changed some 087 * abstract methods to empty implementations (DG); 088 * 28-Oct-2002 : Added a getBackgroundImage() method (DG); 089 * 21-Nov-2002 : Added a plot index for identifying subplots in combined and 090 * overlaid charts (DG); 091 * 22-Nov-2002 : Changed all attributes from 'protected' to 'private'. Added 092 * dataAreaRatio attribute from David M O'Donnell's code (DG); 093 * 09-Jan-2003 : Integrated fix for plot border contributed by Gideon 094 * Krause (DG); 095 * 17-Jan-2003 : Moved to com.jrefinery.chart.plot (DG); 096 * 23-Jan-2003 : Removed one constructor (DG); 097 * 26-Mar-2003 : Implemented Serializable (DG); 098 * 14-Jul-2003 : Moved the dataset and secondaryDataset attributes to the 099 * CategoryPlot and XYPlot classes (DG); 100 * 21-Jul-2003 : Moved DrawingSupplier from CategoryPlot and XYPlot up to this 101 * class (DG); 102 * 20-Aug-2003 : Implemented Cloneable (DG); 103 * 11-Sep-2003 : Listeners and clone (NB); 104 * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG); 105 * 03-Dec-2003 : Modified draw method to accept anchor (DG); 106 * 12-Mar-2004 : Fixed clipping bug in drawNoDataMessage() method (DG); 107 * 07-Apr-2004 : Modified string bounds calculation (DG); 108 * 04-Nov-2004 : Added default shapes for legend items (DG); 109 * 25-Nov-2004 : Some changes to the clone() method implementation (DG); 110 * 23-Feb-2005 : Implemented new LegendItemSource interface (and also 111 * PublicCloneable) (DG); 112 * 21-Apr-2005 : Replaced Insets with RectangleInsets (DG); 113 * 05-May-2005 : Removed unused draw() method (DG); 114 * 06-Jun-2005 : Fixed bugs in equals() method (DG); 115 * 01-Sep-2005 : Moved dataAreaRatio from here to ContourPlot (DG); 116 * ------------- JFREECHART 1.0.x --------------------------------------------- 117 * 30-Jun-2006 : Added background image alpha - see bug report 1514904 (DG); 118 * 05-Sep-2006 : Implemented the MarkerChangeListener interface (DG); 119 * 11-Jan-2007 : Added some argument checks, event notifications, and many 120 * API doc updates (DG); 121 * 03-Apr-2007 : Made drawBackgroundImage() public (DG); 122 * 07-Jun-2007 : Added new fillBackground() method to handle GradientPaint 123 * taking into account orientation (DG); 124 * 25-Mar-2008 : Added fireChangeEvent() method - see patch 1914411 (DG); 125 * 15-Aug-2008 : Added setDrawingSupplier() method with notify flag (DG); 126 * 13-Jan-2009 : Added notify flag (DG); 127 * 19-Mar-2009 : Added entity support - see patch 2603321 by Peter Kolb (DG); 128 * 24-Jun-2009 : Implemented AnnotationChangeListener (see patch 2809117 by 129 * PK) (DG); 130 * 13-Jul-2009 : Plot background image should be clipped if necessary (DG); 131 * 132 */ 133 134package org.jfree.chart.plot; 135 136import java.awt.AlphaComposite; 137import java.awt.BasicStroke; 138import java.awt.Color; 139import java.awt.Composite; 140import java.awt.Font; 141import java.awt.GradientPaint; 142import java.awt.Graphics2D; 143import java.awt.Image; 144import java.awt.Paint; 145import java.awt.Shape; 146import java.awt.Stroke; 147import java.awt.geom.Ellipse2D; 148import java.awt.geom.Point2D; 149import java.awt.geom.Rectangle2D; 150import java.io.IOException; 151import java.io.ObjectInputStream; 152import java.io.ObjectOutputStream; 153import java.io.Serializable; 154 155import javax.swing.event.EventListenerList; 156 157import org.jfree.chart.JFreeChart; 158import org.jfree.chart.LegendItemCollection; 159import org.jfree.chart.LegendItemSource; 160import org.jfree.chart.annotations.Annotation; 161import org.jfree.chart.axis.AxisLocation; 162import org.jfree.chart.entity.EntityCollection; 163import org.jfree.chart.entity.PlotEntity; 164import org.jfree.chart.event.AnnotationChangeEvent; 165import org.jfree.chart.event.AnnotationChangeListener; 166import org.jfree.chart.event.AxisChangeEvent; 167import org.jfree.chart.event.AxisChangeListener; 168import org.jfree.chart.event.ChartChangeEventType; 169import org.jfree.chart.event.MarkerChangeEvent; 170import org.jfree.chart.event.MarkerChangeListener; 171import org.jfree.chart.event.PlotChangeEvent; 172import org.jfree.chart.event.PlotChangeListener; 173import org.jfree.data.general.DatasetChangeEvent; 174import org.jfree.data.general.DatasetChangeListener; 175import org.jfree.data.general.DatasetGroup; 176import org.jfree.io.SerialUtilities; 177import org.jfree.text.G2TextMeasurer; 178import org.jfree.text.TextBlock; 179import org.jfree.text.TextBlockAnchor; 180import org.jfree.text.TextUtilities; 181import org.jfree.ui.Align; 182import org.jfree.ui.RectangleEdge; 183import org.jfree.ui.RectangleInsets; 184import org.jfree.util.ObjectUtilities; 185import org.jfree.util.PaintUtilities; 186import org.jfree.util.PublicCloneable; 187 188/** 189 * The base class for all plots in JFreeChart. The {@link JFreeChart} class 190 * delegates the drawing of axes and data to the plot. This base class 191 * provides facilities common to most plot types. 192 */ 193public abstract class Plot implements AxisChangeListener, 194 DatasetChangeListener, AnnotationChangeListener, MarkerChangeListener, 195 LegendItemSource, PublicCloneable, Cloneable, Serializable { 196 197 /** For serialization. */ 198 private static final long serialVersionUID = -8831571430103671324L; 199 200 /** Useful constant representing zero. */ 201 public static final Number ZERO = new Integer(0); 202 203 /** The default insets. */ 204 public static final RectangleInsets DEFAULT_INSETS 205 = new RectangleInsets(4.0, 8.0, 4.0, 8.0); 206 207 /** The default outline stroke. */ 208 public static final Stroke DEFAULT_OUTLINE_STROKE = new BasicStroke(0.5f, 209 BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); 210 211 /** The default outline color. */ 212 public static final Paint DEFAULT_OUTLINE_PAINT = Color.gray; 213 214 /** The default foreground alpha transparency. */ 215 public static final float DEFAULT_FOREGROUND_ALPHA = 1.0f; 216 217 /** The default background alpha transparency. */ 218 public static final float DEFAULT_BACKGROUND_ALPHA = 1.0f; 219 220 /** The default background color. */ 221 public static final Paint DEFAULT_BACKGROUND_PAINT = Color.white; 222 223 /** The minimum width at which the plot should be drawn. */ 224 public static final int MINIMUM_WIDTH_TO_DRAW = 10; 225 226 /** The minimum height at which the plot should be drawn. */ 227 public static final int MINIMUM_HEIGHT_TO_DRAW = 10; 228 229 /** A default box shape for legend items. */ 230 public static final Shape DEFAULT_LEGEND_ITEM_BOX 231 = new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0); 232 233 /** A default circle shape for legend items. */ 234 public static final Shape DEFAULT_LEGEND_ITEM_CIRCLE 235 = new Ellipse2D.Double(-4.0, -4.0, 8.0, 8.0); 236 237 /** The parent plot (<code>null</code> if this is the root plot). */ 238 private Plot parent; 239 240 /** The dataset group (to be used for thread synchronisation). */ 241 private DatasetGroup datasetGroup; 242 243 /** The message to display if no data is available. */ 244 private String noDataMessage; 245 246 /** The font used to display the 'no data' message. */ 247 private Font noDataMessageFont; 248 249 /** The paint used to draw the 'no data' message. */ 250 private transient Paint noDataMessagePaint; 251 252 /** Amount of blank space around the plot area. */ 253 private RectangleInsets insets; 254 255 /** 256 * A flag that controls whether or not the plot outline is drawn. 257 * 258 * @since 1.0.6 259 */ 260 private boolean outlineVisible; 261 262 /** The Stroke used to draw an outline around the plot. */ 263 private transient Stroke outlineStroke; 264 265 /** The Paint used to draw an outline around the plot. */ 266 private transient Paint outlinePaint; 267 268 /** An optional color used to fill the plot background. */ 269 private transient Paint backgroundPaint; 270 271 /** An optional image for the plot background. */ 272 private transient Image backgroundImage; // not currently serialized 273 274 /** The alignment for the background image. */ 275 private int backgroundImageAlignment = Align.FIT; 276 277 /** The alpha value used to draw the background image. */ 278 private float backgroundImageAlpha = 0.5f; 279 280 /** The alpha-transparency for the plot. */ 281 private float foregroundAlpha; 282 283 /** The alpha transparency for the background paint. */ 284 private float backgroundAlpha; 285 286 /** The drawing supplier. */ 287 private DrawingSupplier drawingSupplier; 288 289 /** Storage for registered change listeners. */ 290 private transient EventListenerList listenerList; 291 292 /** 293 * A flag that controls whether or not the plot will notify listeners 294 * of changes (defaults to true, but sometimes it is useful to disable 295 * this). 296 * 297 * @since 1.0.13 298 */ 299 private boolean notify; 300 301 /** 302 * Creates a new plot. 303 */ 304 protected Plot() { 305 306 this.parent = null; 307 this.insets = DEFAULT_INSETS; 308 this.backgroundPaint = DEFAULT_BACKGROUND_PAINT; 309 this.backgroundAlpha = DEFAULT_BACKGROUND_ALPHA; 310 this.backgroundImage = null; 311 this.outlineVisible = true; 312 this.outlineStroke = DEFAULT_OUTLINE_STROKE; 313 this.outlinePaint = DEFAULT_OUTLINE_PAINT; 314 this.foregroundAlpha = DEFAULT_FOREGROUND_ALPHA; 315 316 this.noDataMessage = null; 317 this.noDataMessageFont = new Font("SansSerif", Font.PLAIN, 12); 318 this.noDataMessagePaint = Color.black; 319 320 this.drawingSupplier = new DefaultDrawingSupplier(); 321 322 this.notify = true; 323 this.listenerList = new EventListenerList(); 324 325 } 326 327 /** 328 * Returns the dataset group for the plot (not currently used). 329 * 330 * @return The dataset group. 331 * 332 * @see #setDatasetGroup(DatasetGroup) 333 */ 334 public DatasetGroup getDatasetGroup() { 335 return this.datasetGroup; 336 } 337 338 /** 339 * Sets the dataset group (not currently used). 340 * 341 * @param group the dataset group (<code>null</code> permitted). 342 * 343 * @see #getDatasetGroup() 344 */ 345 protected void setDatasetGroup(DatasetGroup group) { 346 this.datasetGroup = group; 347 } 348 349 /** 350 * Returns the string that is displayed when the dataset is empty or 351 * <code>null</code>. 352 * 353 * @return The 'no data' message (<code>null</code> possible). 354 * 355 * @see #setNoDataMessage(String) 356 * @see #getNoDataMessageFont() 357 * @see #getNoDataMessagePaint() 358 */ 359 public String getNoDataMessage() { 360 return this.noDataMessage; 361 } 362 363 /** 364 * Sets the message that is displayed when the dataset is empty or 365 * <code>null</code>, and sends a {@link PlotChangeEvent} to all registered 366 * listeners. 367 * 368 * @param message the message (<code>null</code> permitted). 369 * 370 * @see #getNoDataMessage() 371 */ 372 public void setNoDataMessage(String message) { 373 this.noDataMessage = message; 374 fireChangeEvent(); 375 } 376 377 /** 378 * Returns the font used to display the 'no data' message. 379 * 380 * @return The font (never <code>null</code>). 381 * 382 * @see #setNoDataMessageFont(Font) 383 * @see #getNoDataMessage() 384 */ 385 public Font getNoDataMessageFont() { 386 return this.noDataMessageFont; 387 } 388 389 /** 390 * Sets the font used to display the 'no data' message and sends a 391 * {@link PlotChangeEvent} to all registered listeners. 392 * 393 * @param font the font (<code>null</code> not permitted). 394 * 395 * @see #getNoDataMessageFont() 396 */ 397 public void setNoDataMessageFont(Font font) { 398 if (font == null) { 399 throw new IllegalArgumentException("Null 'font' argument."); 400 } 401 this.noDataMessageFont = font; 402 fireChangeEvent(); 403 } 404 405 /** 406 * Returns the paint used to display the 'no data' message. 407 * 408 * @return The paint (never <code>null</code>). 409 * 410 * @see #setNoDataMessagePaint(Paint) 411 * @see #getNoDataMessage() 412 */ 413 public Paint getNoDataMessagePaint() { 414 return this.noDataMessagePaint; 415 } 416 417 /** 418 * Sets the paint used to display the 'no data' message and sends a 419 * {@link PlotChangeEvent} to all registered listeners. 420 * 421 * @param paint the paint (<code>null</code> not permitted). 422 * 423 * @see #getNoDataMessagePaint() 424 */ 425 public void setNoDataMessagePaint(Paint paint) { 426 if (paint == null) { 427 throw new IllegalArgumentException("Null 'paint' argument."); 428 } 429 this.noDataMessagePaint = paint; 430 fireChangeEvent(); 431 } 432 433 /** 434 * Returns a short string describing the plot type. 435 * <P> 436 * Note: this gets used in the chart property editing user interface, 437 * but there needs to be a better mechanism for identifying the plot type. 438 * 439 * @return A short string describing the plot type (never 440 * <code>null</code>). 441 */ 442 public abstract String getPlotType(); 443 444 /** 445 * Returns the parent plot (or <code>null</code> if this plot is not part 446 * of a combined plot). 447 * 448 * @return The parent plot. 449 * 450 * @see #setParent(Plot) 451 * @see #getRootPlot() 452 */ 453 public Plot getParent() { 454 return this.parent; 455 } 456 457 /** 458 * Sets the parent plot. This method is intended for internal use, you 459 * shouldn't need to call it directly. 460 * 461 * @param parent the parent plot (<code>null</code> permitted). 462 * 463 * @see #getParent() 464 */ 465 public void setParent(Plot parent) { 466 this.parent = parent; 467 } 468 469 /** 470 * Returns the root plot. 471 * 472 * @return The root plot. 473 * 474 * @see #getParent() 475 */ 476 public Plot getRootPlot() { 477 478 Plot p = getParent(); 479 if (p == null) { 480 return this; 481 } 482 return p.getRootPlot(); 483 484 } 485 486 /** 487 * Returns <code>true</code> if this plot is part of a combined plot 488 * structure (that is, {@link #getParent()} returns a non-<code>null</code> 489 * value), and <code>false</code> otherwise. 490 * 491 * @return <code>true</code> if this plot is part of a combined plot 492 * structure. 493 * 494 * @see #getParent() 495 */ 496 public boolean isSubplot() { 497 return (getParent() != null); 498 } 499 500 /** 501 * Returns the insets for the plot area. 502 * 503 * @return The insets (never <code>null</code>). 504 * 505 * @see #setInsets(RectangleInsets) 506 */ 507 public RectangleInsets getInsets() { 508 return this.insets; 509 } 510 511 /** 512 * Sets the insets for the plot and sends a {@link PlotChangeEvent} to 513 * all registered listeners. 514 * 515 * @param insets the new insets (<code>null</code> not permitted). 516 * 517 * @see #getInsets() 518 * @see #setInsets(RectangleInsets, boolean) 519 */ 520 public void setInsets(RectangleInsets insets) { 521 setInsets(insets, true); 522 } 523 524 /** 525 * Sets the insets for the plot and, if requested, and sends a 526 * {@link PlotChangeEvent} to all registered listeners. 527 * 528 * @param insets the new insets (<code>null</code> not permitted). 529 * @param notify a flag that controls whether the registered listeners are 530 * notified. 531 * 532 * @see #getInsets() 533 * @see #setInsets(RectangleInsets) 534 */ 535 public void setInsets(RectangleInsets insets, boolean notify) { 536 if (insets == null) { 537 throw new IllegalArgumentException("Null 'insets' argument."); 538 } 539 if (!this.insets.equals(insets)) { 540 this.insets = insets; 541 if (notify) { 542 fireChangeEvent(); 543 } 544 } 545 546 } 547 548 /** 549 * Returns the background color of the plot area. 550 * 551 * @return The paint (possibly <code>null</code>). 552 * 553 * @see #setBackgroundPaint(Paint) 554 */ 555 public Paint getBackgroundPaint() { 556 return this.backgroundPaint; 557 } 558 559 /** 560 * Sets the background color of the plot area and sends a 561 * {@link PlotChangeEvent} to all registered listeners. 562 * 563 * @param paint the paint (<code>null</code> permitted). 564 * 565 * @see #getBackgroundPaint() 566 */ 567 public void setBackgroundPaint(Paint paint) { 568 569 if (paint == null) { 570 if (this.backgroundPaint != null) { 571 this.backgroundPaint = null; 572 fireChangeEvent(); 573 } 574 } 575 else { 576 if (this.backgroundPaint != null) { 577 if (this.backgroundPaint.equals(paint)) { 578 return; // nothing to do 579 } 580 } 581 this.backgroundPaint = paint; 582 fireChangeEvent(); 583 } 584 585 } 586 587 /** 588 * Returns the alpha transparency of the plot area background. 589 * 590 * @return The alpha transparency. 591 * 592 * @see #setBackgroundAlpha(float) 593 */ 594 public float getBackgroundAlpha() { 595 return this.backgroundAlpha; 596 } 597 598 /** 599 * Sets the alpha transparency of the plot area background, and notifies 600 * registered listeners that the plot has been modified. 601 * 602 * @param alpha the new alpha value (in the range 0.0f to 1.0f). 603 * 604 * @see #getBackgroundAlpha() 605 */ 606 public void setBackgroundAlpha(float alpha) { 607 if (this.backgroundAlpha != alpha) { 608 this.backgroundAlpha = alpha; 609 fireChangeEvent(); 610 } 611 } 612 613 /** 614 * Returns the drawing supplier for the plot. 615 * 616 * @return The drawing supplier (possibly <code>null</code>). 617 * 618 * @see #setDrawingSupplier(DrawingSupplier) 619 */ 620 public DrawingSupplier getDrawingSupplier() { 621 DrawingSupplier result = null; 622 Plot p = getParent(); 623 if (p != null) { 624 result = p.getDrawingSupplier(); 625 } 626 else { 627 result = this.drawingSupplier; 628 } 629 return result; 630 } 631 632 /** 633 * Sets the drawing supplier for the plot and sends a 634 * {@link PlotChangeEvent} to all registered listeners. The drawing 635 * supplier is responsible for supplying a limitless (possibly repeating) 636 * sequence of <code>Paint</code>, <code>Stroke</code> and 637 * <code>Shape</code> objects that the plot's renderer(s) can use to 638 * populate its (their) tables. 639 * 640 * @param supplier the new supplier. 641 * 642 * @see #getDrawingSupplier() 643 */ 644 public void setDrawingSupplier(DrawingSupplier supplier) { 645 this.drawingSupplier = supplier; 646 fireChangeEvent(); 647 } 648 649 /** 650 * Sets the drawing supplier for the plot and, if requested, sends a 651 * {@link PlotChangeEvent} to all registered listeners. The drawing 652 * supplier is responsible for supplying a limitless (possibly repeating) 653 * sequence of <code>Paint</code>, <code>Stroke</code> and 654 * <code>Shape</code> objects that the plot's renderer(s) can use to 655 * populate its (their) tables. 656 * 657 * @param supplier the new supplier. 658 * @param notify notify listeners? 659 * 660 * @see #getDrawingSupplier() 661 * 662 * @since 1.0.11 663 */ 664 public void setDrawingSupplier(DrawingSupplier supplier, boolean notify) { 665 this.drawingSupplier = supplier; 666 if (notify) { 667 fireChangeEvent(); 668 } 669 } 670 671 /** 672 * Returns the background image that is used to fill the plot's background 673 * area. 674 * 675 * @return The image (possibly <code>null</code>). 676 * 677 * @see #setBackgroundImage(Image) 678 */ 679 public Image getBackgroundImage() { 680 return this.backgroundImage; 681 } 682 683 /** 684 * Sets the background image for the plot and sends a 685 * {@link PlotChangeEvent} to all registered listeners. 686 * 687 * @param image the image (<code>null</code> permitted). 688 * 689 * @see #getBackgroundImage() 690 */ 691 public void setBackgroundImage(Image image) { 692 this.backgroundImage = image; 693 fireChangeEvent(); 694 } 695 696 /** 697 * Returns the background image alignment. Alignment constants are defined 698 * in the <code>org.jfree.ui.Align</code> class in the JCommon class 699 * library. 700 * 701 * @return The alignment. 702 * 703 * @see #setBackgroundImageAlignment(int) 704 */ 705 public int getBackgroundImageAlignment() { 706 return this.backgroundImageAlignment; 707 } 708 709 /** 710 * Sets the alignment for the background image and sends a 711 * {@link PlotChangeEvent} to all registered listeners. Alignment options 712 * are defined by the {@link org.jfree.ui.Align} class in the JCommon 713 * class library. 714 * 715 * @param alignment the alignment. 716 * 717 * @see #getBackgroundImageAlignment() 718 */ 719 public void setBackgroundImageAlignment(int alignment) { 720 if (this.backgroundImageAlignment != alignment) { 721 this.backgroundImageAlignment = alignment; 722 fireChangeEvent(); 723 } 724 } 725 726 /** 727 * Returns the alpha transparency used to draw the background image. This 728 * is a value in the range 0.0f to 1.0f, where 0.0f is fully transparent 729 * and 1.0f is fully opaque. 730 * 731 * @return The alpha transparency. 732 * 733 * @see #setBackgroundImageAlpha(float) 734 */ 735 public float getBackgroundImageAlpha() { 736 return this.backgroundImageAlpha; 737 } 738 739 /** 740 * Sets the alpha transparency used when drawing the background image. 741 * 742 * @param alpha the alpha transparency (in the range 0.0f to 1.0f, where 743 * 0.0f is fully transparent, and 1.0f is fully opaque). 744 * 745 * @throws IllegalArgumentException if <code>alpha</code> is not within 746 * the specified range. 747 * 748 * @see #getBackgroundImageAlpha() 749 */ 750 public void setBackgroundImageAlpha(float alpha) { 751 if (alpha < 0.0f || alpha > 1.0f) 752 throw new IllegalArgumentException( 753 "The 'alpha' value must be in the range 0.0f to 1.0f."); 754 if (this.backgroundImageAlpha != alpha) { 755 this.backgroundImageAlpha = alpha; 756 fireChangeEvent(); 757 } 758 } 759 760 /** 761 * Returns the flag that controls whether or not the plot outline is 762 * drawn. The default value is <code>true</code>. Note that for 763 * historical reasons, the plot's outline paint and stroke can take on 764 * <code>null</code> values, in which case the outline will not be drawn 765 * even if this flag is set to <code>true</code>. 766 * 767 * @return The outline visibility flag. 768 * 769 * @since 1.0.6 770 * 771 * @see #setOutlineVisible(boolean) 772 */ 773 public boolean isOutlineVisible() { 774 return this.outlineVisible; 775 } 776 777 /** 778 * Sets the flag that controls whether or not the plot's outline is 779 * drawn, and sends a {@link PlotChangeEvent} to all registered listeners. 780 * 781 * @param visible the new flag value. 782 * 783 * @since 1.0.6 784 * 785 * @see #isOutlineVisible() 786 */ 787 public void setOutlineVisible(boolean visible) { 788 this.outlineVisible = visible; 789 fireChangeEvent(); 790 } 791 792 /** 793 * Returns the stroke used to outline the plot area. 794 * 795 * @return The stroke (possibly <code>null</code>). 796 * 797 * @see #setOutlineStroke(Stroke) 798 */ 799 public Stroke getOutlineStroke() { 800 return this.outlineStroke; 801 } 802 803 /** 804 * Sets the stroke used to outline the plot area and sends a 805 * {@link PlotChangeEvent} to all registered listeners. If you set this 806 * attribute to <code>null</code>, no outline will be drawn. 807 * 808 * @param stroke the stroke (<code>null</code> permitted). 809 * 810 * @see #getOutlineStroke() 811 */ 812 public void setOutlineStroke(Stroke stroke) { 813 if (stroke == null) { 814 if (this.outlineStroke != null) { 815 this.outlineStroke = null; 816 fireChangeEvent(); 817 } 818 } 819 else { 820 if (this.outlineStroke != null) { 821 if (this.outlineStroke.equals(stroke)) { 822 return; // nothing to do 823 } 824 } 825 this.outlineStroke = stroke; 826 fireChangeEvent(); 827 } 828 } 829 830 /** 831 * Returns the color used to draw the outline of the plot area. 832 * 833 * @return The color (possibly <code>null</code>). 834 * 835 * @see #setOutlinePaint(Paint) 836 */ 837 public Paint getOutlinePaint() { 838 return this.outlinePaint; 839 } 840 841 /** 842 * Sets the paint used to draw the outline of the plot area and sends a 843 * {@link PlotChangeEvent} to all registered listeners. If you set this 844 * attribute to <code>null</code>, no outline will be drawn. 845 * 846 * @param paint the paint (<code>null</code> permitted). 847 * 848 * @see #getOutlinePaint() 849 */ 850 public void setOutlinePaint(Paint paint) { 851 if (paint == null) { 852 if (this.outlinePaint != null) { 853 this.outlinePaint = null; 854 fireChangeEvent(); 855 } 856 } 857 else { 858 if (this.outlinePaint != null) { 859 if (this.outlinePaint.equals(paint)) { 860 return; // nothing to do 861 } 862 } 863 this.outlinePaint = paint; 864 fireChangeEvent(); 865 } 866 } 867 868 /** 869 * Returns the alpha-transparency for the plot foreground. 870 * 871 * @return The alpha-transparency. 872 * 873 * @see #setForegroundAlpha(float) 874 */ 875 public float getForegroundAlpha() { 876 return this.foregroundAlpha; 877 } 878 879 /** 880 * Sets the alpha-transparency for the plot and sends a 881 * {@link PlotChangeEvent} to all registered listeners. 882 * 883 * @param alpha the new alpha transparency. 884 * 885 * @see #getForegroundAlpha() 886 */ 887 public void setForegroundAlpha(float alpha) { 888 if (this.foregroundAlpha != alpha) { 889 this.foregroundAlpha = alpha; 890 fireChangeEvent(); 891 } 892 } 893 894 /** 895 * Returns the legend items for the plot. By default, this method returns 896 * <code>null</code>. Subclasses should override to return a 897 * {@link LegendItemCollection}. 898 * 899 * @return The legend items for the plot (possibly <code>null</code>). 900 */ 901 public LegendItemCollection getLegendItems() { 902 return null; 903 } 904 905 /** 906 * Returns a flag that controls whether or not change events are sent to 907 * registered listeners. 908 * 909 * @return A boolean. 910 * 911 * @see #setNotify(boolean) 912 * 913 * @since 1.0.13 914 */ 915 public boolean isNotify() { 916 return this.notify; 917 } 918 919 /** 920 * Sets a flag that controls whether or not listeners receive 921 * {@link PlotChangeEvent} notifications. 922 * 923 * @param notify a boolean. 924 * 925 * @see #isNotify() 926 * 927 * @since 1.0.13 928 */ 929 public void setNotify(boolean notify) { 930 this.notify = notify; 931 // if the flag is being set to true, there may be queued up changes... 932 if (notify) { 933 notifyListeners(new PlotChangeEvent(this)); 934 } 935 } 936 937 /** 938 * Registers an object for notification of changes to the plot. 939 * 940 * @param listener the object to be registered. 941 * 942 * @see #removeChangeListener(PlotChangeListener) 943 */ 944 public void addChangeListener(PlotChangeListener listener) { 945 this.listenerList.add(PlotChangeListener.class, listener); 946 } 947 948 /** 949 * Unregisters an object for notification of changes to the plot. 950 * 951 * @param listener the object to be unregistered. 952 * 953 * @see #addChangeListener(PlotChangeListener) 954 */ 955 public void removeChangeListener(PlotChangeListener listener) { 956 this.listenerList.remove(PlotChangeListener.class, listener); 957 } 958 959 /** 960 * Notifies all registered listeners that the plot has been modified. 961 * 962 * @param event information about the change event. 963 */ 964 public void notifyListeners(PlotChangeEvent event) { 965 // if the 'notify' flag has been switched to false, we don't notify 966 // the listeners 967 if (!this.notify) { 968 return; 969 } 970 Object[] listeners = this.listenerList.getListenerList(); 971 for (int i = listeners.length - 2; i >= 0; i -= 2) { 972 if (listeners[i] == PlotChangeListener.class) { 973 ((PlotChangeListener) listeners[i + 1]).plotChanged(event); 974 } 975 } 976 } 977 978 /** 979 * Sends a {@link PlotChangeEvent} to all registered listeners. 980 * 981 * @since 1.0.10 982 */ 983 protected void fireChangeEvent() { 984 notifyListeners(new PlotChangeEvent(this)); 985 } 986 987 /** 988 * Draws the plot within the specified area. The anchor is a point on the 989 * chart that is specified externally (for instance, it may be the last 990 * point of the last mouse click performed by the user) - plots can use or 991 * ignore this value as they see fit. 992 * <br><br> 993 * Subclasses need to provide an implementation of this method, obviously. 994 * 995 * @param g2 the graphics device. 996 * @param area the plot area. 997 * @param anchor the anchor point (<code>null</code> permitted). 998 * @param parentState the parent state (if any). 999 * @param info carries back plot rendering info. 1000 */ 1001 public abstract void draw(Graphics2D g2, 1002 Rectangle2D area, 1003 Point2D anchor, 1004 PlotState parentState, 1005 PlotRenderingInfo info); 1006 1007 /** 1008 * Draws the plot background (the background color and/or image). 1009 * <P> 1010 * This method will be called during the chart drawing process and is 1011 * declared public so that it can be accessed by the renderers used by 1012 * certain subclasses. You shouldn't need to call this method directly. 1013 * 1014 * @param g2 the graphics device. 1015 * @param area the area within which the plot should be drawn. 1016 */ 1017 public void drawBackground(Graphics2D g2, Rectangle2D area) { 1018 // some subclasses override this method completely, so don't put 1019 // anything here that *must* be done 1020 fillBackground(g2, area); 1021 drawBackgroundImage(g2, area); 1022 } 1023 1024 /** 1025 * Fills the specified area with the background paint. 1026 * 1027 * @param g2 the graphics device. 1028 * @param area the area. 1029 * 1030 * @see #getBackgroundPaint() 1031 * @see #getBackgroundAlpha() 1032 * @see #fillBackground(Graphics2D, Rectangle2D, PlotOrientation) 1033 */ 1034 protected void fillBackground(Graphics2D g2, Rectangle2D area) { 1035 fillBackground(g2, area, PlotOrientation.VERTICAL); 1036 } 1037 1038 /** 1039 * Fills the specified area with the background paint. If the background 1040 * paint is an instance of <code>GradientPaint</code>, the gradient will 1041 * run in the direction suggested by the plot's orientation. 1042 * 1043 * @param g2 the graphics target. 1044 * @param area the plot area. 1045 * @param orientation the plot orientation (<code>null</code> not 1046 * permitted). 1047 * 1048 * @since 1.0.6 1049 */ 1050 protected void fillBackground(Graphics2D g2, Rectangle2D area, 1051 PlotOrientation orientation) { 1052 if (orientation == null) { 1053 throw new IllegalArgumentException("Null 'orientation' argument."); 1054 } 1055 if (this.backgroundPaint == null) { 1056 return; 1057 } 1058 Paint p = this.backgroundPaint; 1059 if (p instanceof GradientPaint) { 1060 GradientPaint gp = (GradientPaint) p; 1061 if (orientation == PlotOrientation.VERTICAL) { 1062 p = new GradientPaint((float) area.getCenterX(), 1063 (float) area.getMaxY(), gp.getColor1(), 1064 (float) area.getCenterX(), (float) area.getMinY(), 1065 gp.getColor2()); 1066 } 1067 else if (orientation == PlotOrientation.HORIZONTAL) { 1068 p = new GradientPaint((float) area.getMinX(), 1069 (float) area.getCenterY(), gp.getColor1(), 1070 (float) area.getMaxX(), (float) area.getCenterY(), 1071 gp.getColor2()); 1072 } 1073 } 1074 Composite originalComposite = g2.getComposite(); 1075 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1076 this.backgroundAlpha)); 1077 g2.setPaint(p); 1078 g2.fill(area); 1079 g2.setComposite(originalComposite); 1080 } 1081 1082 /** 1083 * Draws the background image (if there is one) aligned within the 1084 * specified area. 1085 * 1086 * @param g2 the graphics device. 1087 * @param area the area. 1088 * 1089 * @see #getBackgroundImage() 1090 * @see #getBackgroundImageAlignment() 1091 * @see #getBackgroundImageAlpha() 1092 */ 1093 public void drawBackgroundImage(Graphics2D g2, Rectangle2D area) { 1094 if (this.backgroundImage == null) { 1095 return; // nothing to do 1096 } 1097 Composite savedComposite = g2.getComposite(); 1098 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1099 this.backgroundImageAlpha)); 1100 Rectangle2D dest = new Rectangle2D.Double(0.0, 0.0, 1101 this.backgroundImage.getWidth(null), 1102 this.backgroundImage.getHeight(null)); 1103 Align.align(dest, area, this.backgroundImageAlignment); 1104 Shape savedClip = g2.getClip(); 1105 g2.clip(area); 1106 g2.drawImage(this.backgroundImage, (int) dest.getX(), 1107 (int) dest.getY(), (int) dest.getWidth() + 1, 1108 (int) dest.getHeight() + 1, null); 1109 g2.setClip(savedClip); 1110 g2.setComposite(savedComposite); 1111 } 1112 1113 /** 1114 * Draws the plot outline. This method will be called during the chart 1115 * drawing process and is declared public so that it can be accessed by the 1116 * renderers used by certain subclasses. You shouldn't need to call this 1117 * method directly. 1118 * 1119 * @param g2 the graphics device. 1120 * @param area the area within which the plot should be drawn. 1121 */ 1122 public void drawOutline(Graphics2D g2, Rectangle2D area) { 1123 if (!this.outlineVisible) { 1124 return; 1125 } 1126 if ((this.outlineStroke != null) && (this.outlinePaint != null)) { 1127 g2.setStroke(this.outlineStroke); 1128 g2.setPaint(this.outlinePaint); 1129 g2.draw(area); 1130 } 1131 } 1132 1133 /** 1134 * Draws a message to state that there is no data to plot. 1135 * 1136 * @param g2 the graphics device. 1137 * @param area the area within which the plot should be drawn. 1138 */ 1139 protected void drawNoDataMessage(Graphics2D g2, Rectangle2D area) { 1140 Shape savedClip = g2.getClip(); 1141 g2.clip(area); 1142 String message = this.noDataMessage; 1143 if (message != null) { 1144 g2.setFont(this.noDataMessageFont); 1145 g2.setPaint(this.noDataMessagePaint); 1146 TextBlock block = TextUtilities.createTextBlock( 1147 this.noDataMessage, this.noDataMessageFont, 1148 this.noDataMessagePaint, 0.9f * (float) area.getWidth(), 1149 new G2TextMeasurer(g2)); 1150 block.draw(g2, (float) area.getCenterX(), 1151 (float) area.getCenterY(), TextBlockAnchor.CENTER); 1152 } 1153 g2.setClip(savedClip); 1154 } 1155 1156 /** 1157 * Creates a plot entity that contains a reference to the plot and the 1158 * data area as shape. 1159 * 1160 * @param dataArea the data area used as hot spot for the entity. 1161 * @param plotState the plot rendering info containing a reference to the 1162 * EntityCollection. 1163 * @param toolTip the tool tip (defined in the respective Plot 1164 * subclass) (<code>null</code> permitted). 1165 * @param urlText the url (defined in the respective Plot subclass) 1166 * (<code>null</code> permitted). 1167 * 1168 * @since 1.0.13 1169 */ 1170 protected void createAndAddEntity(Rectangle2D dataArea, 1171 PlotRenderingInfo plotState, String toolTip, String urlText) { 1172 if (plotState != null && plotState.getOwner() != null) { 1173 EntityCollection e = plotState.getOwner().getEntityCollection(); 1174 if (e != null) { 1175 e.add(new PlotEntity(dataArea, this, toolTip, urlText)); 1176 } 1177 } 1178 } 1179 1180 /** 1181 * Handles a 'click' on the plot. Since the plot does not maintain any 1182 * information about where it has been drawn, the plot rendering info is 1183 * supplied as an argument so that the plot dimensions can be determined. 1184 * 1185 * @param x the x coordinate (in Java2D space). 1186 * @param y the y coordinate (in Java2D space). 1187 * @param info an object containing information about the dimensions of 1188 * the plot. 1189 */ 1190 public void handleClick(int x, int y, PlotRenderingInfo info) { 1191 // provides a 'no action' default 1192 } 1193 1194 /** 1195 * Performs a zoom on the plot. Subclasses should override if zooming is 1196 * appropriate for the type of plot. 1197 * 1198 * @param percent the zoom percentage. 1199 */ 1200 public void zoom(double percent) { 1201 // do nothing by default. 1202 } 1203 1204 /** 1205 * Receives notification of a change to an {@link Annotation} added to 1206 * this plot. 1207 * 1208 * @param event information about the event (not used here). 1209 * 1210 * @since 1.0.14 1211 */ 1212 public void annotationChanged(AnnotationChangeEvent event) { 1213 fireChangeEvent(); 1214 } 1215 1216 /** 1217 * Receives notification of a change to one of the plot's axes. 1218 * 1219 * @param event information about the event (not used here). 1220 */ 1221 public void axisChanged(AxisChangeEvent event) { 1222 fireChangeEvent(); 1223 } 1224 1225 /** 1226 * Receives notification of a change to the plot's dataset. 1227 * <P> 1228 * The plot reacts by passing on a plot change event to all registered 1229 * listeners. 1230 * 1231 * @param event information about the event (not used here). 1232 */ 1233 public void datasetChanged(DatasetChangeEvent event) { 1234 PlotChangeEvent newEvent = new PlotChangeEvent(this); 1235 newEvent.setType(ChartChangeEventType.DATASET_UPDATED); 1236 notifyListeners(newEvent); 1237 } 1238 1239 /** 1240 * Receives notification of a change to a marker that is assigned to the 1241 * plot. 1242 * 1243 * @param event the event. 1244 * 1245 * @since 1.0.3 1246 */ 1247 public void markerChanged(MarkerChangeEvent event) { 1248 fireChangeEvent(); 1249 } 1250 1251 /** 1252 * Adjusts the supplied x-value. 1253 * 1254 * @param x the x-value. 1255 * @param w1 width 1. 1256 * @param w2 width 2. 1257 * @param edge the edge (left or right). 1258 * 1259 * @return The adjusted x-value. 1260 */ 1261 protected double getRectX(double x, double w1, double w2, 1262 RectangleEdge edge) { 1263 1264 double result = x; 1265 if (edge == RectangleEdge.LEFT) { 1266 result = result + w1; 1267 } 1268 else if (edge == RectangleEdge.RIGHT) { 1269 result = result + w2; 1270 } 1271 return result; 1272 1273 } 1274 1275 /** 1276 * Adjusts the supplied y-value. 1277 * 1278 * @param y the x-value. 1279 * @param h1 height 1. 1280 * @param h2 height 2. 1281 * @param edge the edge (top or bottom). 1282 * 1283 * @return The adjusted y-value. 1284 */ 1285 protected double getRectY(double y, double h1, double h2, 1286 RectangleEdge edge) { 1287 1288 double result = y; 1289 if (edge == RectangleEdge.TOP) { 1290 result = result + h1; 1291 } 1292 else if (edge == RectangleEdge.BOTTOM) { 1293 result = result + h2; 1294 } 1295 return result; 1296 1297 } 1298 1299 /** 1300 * Tests this plot for equality with another object. 1301 * 1302 * @param obj the object (<code>null</code> permitted). 1303 * 1304 * @return <code>true</code> or <code>false</code>. 1305 */ 1306 public boolean equals(Object obj) { 1307 if (obj == this) { 1308 return true; 1309 } 1310 if (!(obj instanceof Plot)) { 1311 return false; 1312 } 1313 Plot that = (Plot) obj; 1314 if (!ObjectUtilities.equal(this.noDataMessage, that.noDataMessage)) { 1315 return false; 1316 } 1317 if (!ObjectUtilities.equal( 1318 this.noDataMessageFont, that.noDataMessageFont 1319 )) { 1320 return false; 1321 } 1322 if (!PaintUtilities.equal(this.noDataMessagePaint, 1323 that.noDataMessagePaint)) { 1324 return false; 1325 } 1326 if (!ObjectUtilities.equal(this.insets, that.insets)) { 1327 return false; 1328 } 1329 if (this.outlineVisible != that.outlineVisible) { 1330 return false; 1331 } 1332 if (!ObjectUtilities.equal(this.outlineStroke, that.outlineStroke)) { 1333 return false; 1334 } 1335 if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) { 1336 return false; 1337 } 1338 if (!PaintUtilities.equal(this.backgroundPaint, that.backgroundPaint)) { 1339 return false; 1340 } 1341 if (!ObjectUtilities.equal(this.backgroundImage, 1342 that.backgroundImage)) { 1343 return false; 1344 } 1345 if (this.backgroundImageAlignment != that.backgroundImageAlignment) { 1346 return false; 1347 } 1348 if (this.backgroundImageAlpha != that.backgroundImageAlpha) { 1349 return false; 1350 } 1351 if (this.foregroundAlpha != that.foregroundAlpha) { 1352 return false; 1353 } 1354 if (this.backgroundAlpha != that.backgroundAlpha) { 1355 return false; 1356 } 1357 if (!this.drawingSupplier.equals(that.drawingSupplier)) { 1358 return false; 1359 } 1360 if (this.notify != that.notify) { 1361 return false; 1362 } 1363 return true; 1364 } 1365 1366 /** 1367 * Creates a clone of the plot. 1368 * 1369 * @return A clone. 1370 * 1371 * @throws CloneNotSupportedException if some component of the plot does not 1372 * support cloning. 1373 */ 1374 public Object clone() throws CloneNotSupportedException { 1375 1376 Plot clone = (Plot) super.clone(); 1377 // private Plot parent <-- don't clone the parent plot, but take care 1378 // childs in combined plots instead 1379 if (this.datasetGroup != null) { 1380 clone.datasetGroup 1381 = (DatasetGroup) ObjectUtilities.clone(this.datasetGroup); 1382 } 1383 clone.drawingSupplier 1384 = (DrawingSupplier) ObjectUtilities.clone(this.drawingSupplier); 1385 clone.listenerList = new EventListenerList(); 1386 return clone; 1387 1388 } 1389 1390 /** 1391 * Provides serialization support. 1392 * 1393 * @param stream the output stream. 1394 * 1395 * @throws IOException if there is an I/O error. 1396 */ 1397 private void writeObject(ObjectOutputStream stream) throws IOException { 1398 stream.defaultWriteObject(); 1399 SerialUtilities.writePaint(this.noDataMessagePaint, stream); 1400 SerialUtilities.writeStroke(this.outlineStroke, stream); 1401 SerialUtilities.writePaint(this.outlinePaint, stream); 1402 // backgroundImage 1403 SerialUtilities.writePaint(this.backgroundPaint, stream); 1404 } 1405 1406 /** 1407 * Provides serialization support. 1408 * 1409 * @param stream the input stream. 1410 * 1411 * @throws IOException if there is an I/O error. 1412 * @throws ClassNotFoundException if there is a classpath problem. 1413 */ 1414 private void readObject(ObjectInputStream stream) 1415 throws IOException, ClassNotFoundException { 1416 stream.defaultReadObject(); 1417 this.noDataMessagePaint = SerialUtilities.readPaint(stream); 1418 this.outlineStroke = SerialUtilities.readStroke(stream); 1419 this.outlinePaint = SerialUtilities.readPaint(stream); 1420 // backgroundImage 1421 this.backgroundPaint = SerialUtilities.readPaint(stream); 1422 1423 this.listenerList = new EventListenerList(); 1424 1425 } 1426 1427 /** 1428 * Resolves a domain axis location for a given plot orientation. 1429 * 1430 * @param location the location (<code>null</code> not permitted). 1431 * @param orientation the orientation (<code>null</code> not permitted). 1432 * 1433 * @return The edge (never <code>null</code>). 1434 */ 1435 public static RectangleEdge resolveDomainAxisLocation( 1436 AxisLocation location, PlotOrientation orientation) { 1437 1438 if (location == null) { 1439 throw new IllegalArgumentException("Null 'location' argument."); 1440 } 1441 if (orientation == null) { 1442 throw new IllegalArgumentException("Null 'orientation' argument."); 1443 } 1444 1445 RectangleEdge result = null; 1446 1447 if (location == AxisLocation.TOP_OR_RIGHT) { 1448 if (orientation == PlotOrientation.HORIZONTAL) { 1449 result = RectangleEdge.RIGHT; 1450 } 1451 else if (orientation == PlotOrientation.VERTICAL) { 1452 result = RectangleEdge.TOP; 1453 } 1454 } 1455 else if (location == AxisLocation.TOP_OR_LEFT) { 1456 if (orientation == PlotOrientation.HORIZONTAL) { 1457 result = RectangleEdge.LEFT; 1458 } 1459 else if (orientation == PlotOrientation.VERTICAL) { 1460 result = RectangleEdge.TOP; 1461 } 1462 } 1463 else if (location == AxisLocation.BOTTOM_OR_RIGHT) { 1464 if (orientation == PlotOrientation.HORIZONTAL) { 1465 result = RectangleEdge.RIGHT; 1466 } 1467 else if (orientation == PlotOrientation.VERTICAL) { 1468 result = RectangleEdge.BOTTOM; 1469 } 1470 } 1471 else if (location == AxisLocation.BOTTOM_OR_LEFT) { 1472 if (orientation == PlotOrientation.HORIZONTAL) { 1473 result = RectangleEdge.LEFT; 1474 } 1475 else if (orientation == PlotOrientation.VERTICAL) { 1476 result = RectangleEdge.BOTTOM; 1477 } 1478 } 1479 // the above should cover all the options... 1480 if (result == null) { 1481 throw new IllegalStateException("resolveDomainAxisLocation()"); 1482 } 1483 return result; 1484 1485 } 1486 1487 /** 1488 * Resolves a range axis location for a given plot orientation. 1489 * 1490 * @param location the location (<code>null</code> not permitted). 1491 * @param orientation the orientation (<code>null</code> not permitted). 1492 * 1493 * @return The edge (never <code>null</code>). 1494 */ 1495 public static RectangleEdge resolveRangeAxisLocation( 1496 AxisLocation location, PlotOrientation orientation) { 1497 1498 if (location == null) { 1499 throw new IllegalArgumentException("Null 'location' argument."); 1500 } 1501 if (orientation == null) { 1502 throw new IllegalArgumentException("Null 'orientation' argument."); 1503 } 1504 1505 RectangleEdge result = null; 1506 1507 if (location == AxisLocation.TOP_OR_RIGHT) { 1508 if (orientation == PlotOrientation.HORIZONTAL) { 1509 result = RectangleEdge.TOP; 1510 } 1511 else if (orientation == PlotOrientation.VERTICAL) { 1512 result = RectangleEdge.RIGHT; 1513 } 1514 } 1515 else if (location == AxisLocation.TOP_OR_LEFT) { 1516 if (orientation == PlotOrientation.HORIZONTAL) { 1517 result = RectangleEdge.TOP; 1518 } 1519 else if (orientation == PlotOrientation.VERTICAL) { 1520 result = RectangleEdge.LEFT; 1521 } 1522 } 1523 else if (location == AxisLocation.BOTTOM_OR_RIGHT) { 1524 if (orientation == PlotOrientation.HORIZONTAL) { 1525 result = RectangleEdge.BOTTOM; 1526 } 1527 else if (orientation == PlotOrientation.VERTICAL) { 1528 result = RectangleEdge.RIGHT; 1529 } 1530 } 1531 else if (location == AxisLocation.BOTTOM_OR_LEFT) { 1532 if (orientation == PlotOrientation.HORIZONTAL) { 1533 result = RectangleEdge.BOTTOM; 1534 } 1535 else if (orientation == PlotOrientation.VERTICAL) { 1536 result = RectangleEdge.LEFT; 1537 } 1538 } 1539 1540 // the above should cover all the options... 1541 if (result == null) { 1542 throw new IllegalStateException("resolveRangeAxisLocation()"); 1543 } 1544 return result; 1545 1546 } 1547 1548}