001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2009, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * --------- 028 * Axis.java 029 * --------- 030 * (C) Copyright 2000-2009, by Object Refinery Limited and Contributors. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): Bill Kelemen; 034 * Nicolas Brodu; 035 * Peter Kolb (patches 1934255 and 2603321); 036 * Andrew Mickish (patch 1870189); 037 * 038 * Changes 039 * ------- 040 * 21-Aug-2001 : Added standard header, fixed DOS encoding problem (DG); 041 * 18-Sep-2001 : Updated header (DG); 042 * 07-Nov-2001 : Allow null axis labels (DG); 043 * : Added default font values (DG); 044 * 13-Nov-2001 : Modified the setPlot() method to check compatibility between 045 * the axis and the plot (DG); 046 * 30-Nov-2001 : Changed default font from "Arial" --> "SansSerif" (DG); 047 * 06-Dec-2001 : Allow null in setPlot() method (BK); 048 * 06-Mar-2002 : Added AxisConstants interface (DG); 049 * 23-Apr-2002 : Added a visible property. Moved drawVerticalString to 050 * RefineryUtilities. Added fixedDimension property for use in 051 * combined plots (DG); 052 * 25-Jun-2002 : Removed unnecessary imports (DG); 053 * 05-Sep-2002 : Added attribute for tick mark paint (DG); 054 * 18-Sep-2002 : Fixed errors reported by Checkstyle (DG); 055 * 07-Nov-2002 : Added attributes to control the inside and outside length of 056 * the tick marks (DG); 057 * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG); 058 * 18-Nov-2002 : Added axis location to refreshTicks() parameters (DG); 059 * 15-Jan-2003 : Removed monolithic constructor (DG); 060 * 17-Jan-2003 : Moved plot classes to separate package (DG); 061 * 26-Mar-2003 : Implemented Serializable (DG); 062 * 03-Jul-2003 : Modified reserveSpace method (DG); 063 * 13-Aug-2003 : Implemented Cloneable (DG); 064 * 11-Sep-2003 : Took care of listeners while cloning (NB); 065 * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG); 066 * 06-Nov-2003 : Modified refreshTicks() signature (DG); 067 * 06-Jan-2004 : Added axis line attributes (DG); 068 * 16-Mar-2004 : Added plot state to draw() method (DG); 069 * 07-Apr-2004 : Modified text bounds calculation (DG); 070 * 18-May-2004 : Eliminated AxisConstants.java (DG); 071 * 30-Sep-2004 : Moved drawRotatedString() from RefineryUtilities --> 072 * TextUtilities (DG); 073 * 04-Oct-2004 : Modified getLabelEnclosure() method to treat an empty String 074 * the same way as a null string - see bug 1026521 (DG); 075 * 21-Apr-2005 : Replaced Insets with RectangleInsets (DG); 076 * 26-Apr-2005 : Removed LOGGER (DG); 077 * 01-Jun-2005 : Added hasListener() method for unit testing (DG); 078 * 08-Jun-2005 : Fixed equals() method to handle GradientPaint (DG); 079 * ------------- JFREECHART 1.0.x --------------------------------------------- 080 * 22-Aug-2006 : API doc updates (DG); 081 * 06-Jun-2008 : Added setTickLabelInsets(RectangleInsets, boolean) (DG); 082 * 25-Sep-2008 : Added minor tick support, see patch 1934255 by Peter Kolb (DG); 083 * 26-Sep-2008 : Added fireChangeEvent() method (DG); 084 * 19-Mar-2009 : Added entity support - see patch 2603321 by Peter Kolb (DG); 085 * 086 */ 087 088 package org.jfree.chart.axis; 089 090 import java.awt.BasicStroke; 091 import java.awt.Color; 092 import java.awt.Font; 093 import java.awt.FontMetrics; 094 import java.awt.Graphics2D; 095 import java.awt.Paint; 096 import java.awt.Shape; 097 import java.awt.Stroke; 098 import java.awt.geom.AffineTransform; 099 import java.awt.geom.Line2D; 100 import java.awt.geom.Rectangle2D; 101 import java.io.IOException; 102 import java.io.ObjectInputStream; 103 import java.io.ObjectOutputStream; 104 import java.io.Serializable; 105 import java.util.Arrays; 106 import java.util.EventListener; 107 import java.util.List; 108 109 import javax.swing.event.EventListenerList; 110 111 import org.jfree.chart.entity.AxisEntity; 112 import org.jfree.chart.entity.EntityCollection; 113 import org.jfree.chart.event.AxisChangeEvent; 114 import org.jfree.chart.event.AxisChangeListener; 115 import org.jfree.chart.plot.Plot; 116 import org.jfree.chart.plot.PlotRenderingInfo; 117 import org.jfree.io.SerialUtilities; 118 import org.jfree.text.TextUtilities; 119 import org.jfree.ui.RectangleEdge; 120 import org.jfree.ui.RectangleInsets; 121 import org.jfree.ui.TextAnchor; 122 import org.jfree.util.ObjectUtilities; 123 import org.jfree.util.PaintUtilities; 124 125 /** 126 * The base class for all axes in JFreeChart. Subclasses are divided into 127 * those that display values ({@link ValueAxis}) and those that display 128 * categories ({@link CategoryAxis}). 129 */ 130 public abstract class Axis implements Cloneable, Serializable { 131 132 /** For serialization. */ 133 private static final long serialVersionUID = 7719289504573298271L; 134 135 /** The default axis visibility. */ 136 public static final boolean DEFAULT_AXIS_VISIBLE = true; 137 138 /** The default axis label font. */ 139 public static final Font DEFAULT_AXIS_LABEL_FONT = new Font( 140 "SansSerif", Font.PLAIN, 12); 141 142 /** The default axis label paint. */ 143 public static final Paint DEFAULT_AXIS_LABEL_PAINT = Color.black; 144 145 /** The default axis label insets. */ 146 public static final RectangleInsets DEFAULT_AXIS_LABEL_INSETS 147 = new RectangleInsets(3.0, 3.0, 3.0, 3.0); 148 149 /** The default axis line paint. */ 150 public static final Paint DEFAULT_AXIS_LINE_PAINT = Color.gray; 151 152 /** The default axis line stroke. */ 153 public static final Stroke DEFAULT_AXIS_LINE_STROKE = new BasicStroke(1.0f); 154 155 /** The default tick labels visibility. */ 156 public static final boolean DEFAULT_TICK_LABELS_VISIBLE = true; 157 158 /** The default tick label font. */ 159 public static final Font DEFAULT_TICK_LABEL_FONT = new Font("SansSerif", 160 Font.PLAIN, 10); 161 162 /** The default tick label paint. */ 163 public static final Paint DEFAULT_TICK_LABEL_PAINT = Color.black; 164 165 /** The default tick label insets. */ 166 public static final RectangleInsets DEFAULT_TICK_LABEL_INSETS 167 = new RectangleInsets(2.0, 4.0, 2.0, 4.0); 168 169 /** The default tick marks visible. */ 170 public static final boolean DEFAULT_TICK_MARKS_VISIBLE = true; 171 172 /** The default tick stroke. */ 173 public static final Stroke DEFAULT_TICK_MARK_STROKE = new BasicStroke(1); 174 175 /** The default tick paint. */ 176 public static final Paint DEFAULT_TICK_MARK_PAINT = Color.gray; 177 178 /** The default tick mark inside length. */ 179 public static final float DEFAULT_TICK_MARK_INSIDE_LENGTH = 0.0f; 180 181 /** The default tick mark outside length. */ 182 public static final float DEFAULT_TICK_MARK_OUTSIDE_LENGTH = 2.0f; 183 184 /** A flag indicating whether or not the axis is visible. */ 185 private boolean visible; 186 187 /** The label for the axis. */ 188 private String label; 189 190 /** The font for displaying the axis label. */ 191 private Font labelFont; 192 193 /** The paint for drawing the axis label. */ 194 private transient Paint labelPaint; 195 196 /** The insets for the axis label. */ 197 private RectangleInsets labelInsets; 198 199 /** The label angle. */ 200 private double labelAngle; 201 202 /** A flag that controls whether or not the axis line is visible. */ 203 private boolean axisLineVisible; 204 205 /** The stroke used for the axis line. */ 206 private transient Stroke axisLineStroke; 207 208 /** The paint used for the axis line. */ 209 private transient Paint axisLinePaint; 210 211 /** 212 * A flag that indicates whether or not tick labels are visible for the 213 * axis. 214 */ 215 private boolean tickLabelsVisible; 216 217 /** The font used to display the tick labels. */ 218 private Font tickLabelFont; 219 220 /** The color used to display the tick labels. */ 221 private transient Paint tickLabelPaint; 222 223 /** The blank space around each tick label. */ 224 private RectangleInsets tickLabelInsets; 225 226 /** 227 * A flag that indicates whether or not major tick marks are visible for 228 * the axis. 229 */ 230 private boolean tickMarksVisible; 231 232 /** 233 * The length of the major tick mark inside the data area (zero 234 * permitted). 235 */ 236 private float tickMarkInsideLength; 237 238 /** 239 * The length of the major tick mark outside the data area (zero 240 * permitted). 241 */ 242 private float tickMarkOutsideLength; 243 244 /** 245 * A flag that indicates whether or not minor tick marks are visible for the 246 * axis. 247 * 248 * @since 1.0.12 249 */ 250 private boolean minorTickMarksVisible; 251 252 /** 253 * The length of the minor tick mark inside the data area (zero permitted). 254 * 255 * @since 1.0.12 256 */ 257 private float minorTickMarkInsideLength; 258 259 /** 260 * The length of the minor tick mark outside the data area (zero permitted). 261 * 262 * @since 1.0.12 263 */ 264 private float minorTickMarkOutsideLength; 265 266 /** The stroke used to draw tick marks. */ 267 private transient Stroke tickMarkStroke; 268 269 /** The paint used to draw tick marks. */ 270 private transient Paint tickMarkPaint; 271 272 /** The fixed (horizontal or vertical) dimension for the axis. */ 273 private double fixedDimension; 274 275 /** 276 * A reference back to the plot that the axis is assigned to (can be 277 * <code>null</code>). 278 */ 279 private transient Plot plot; 280 281 /** Storage for registered listeners. */ 282 private transient EventListenerList listenerList; 283 284 /** 285 * Constructs an axis, using default values where necessary. 286 * 287 * @param label the axis label (<code>null</code> permitted). 288 */ 289 protected Axis(String label) { 290 291 this.label = label; 292 this.visible = DEFAULT_AXIS_VISIBLE; 293 this.labelFont = DEFAULT_AXIS_LABEL_FONT; 294 this.labelPaint = DEFAULT_AXIS_LABEL_PAINT; 295 this.labelInsets = DEFAULT_AXIS_LABEL_INSETS; 296 this.labelAngle = 0.0; 297 298 this.axisLineVisible = true; 299 this.axisLinePaint = DEFAULT_AXIS_LINE_PAINT; 300 this.axisLineStroke = DEFAULT_AXIS_LINE_STROKE; 301 302 this.tickLabelsVisible = DEFAULT_TICK_LABELS_VISIBLE; 303 this.tickLabelFont = DEFAULT_TICK_LABEL_FONT; 304 this.tickLabelPaint = DEFAULT_TICK_LABEL_PAINT; 305 this.tickLabelInsets = DEFAULT_TICK_LABEL_INSETS; 306 307 this.tickMarksVisible = DEFAULT_TICK_MARKS_VISIBLE; 308 this.tickMarkStroke = DEFAULT_TICK_MARK_STROKE; 309 this.tickMarkPaint = DEFAULT_TICK_MARK_PAINT; 310 this.tickMarkInsideLength = DEFAULT_TICK_MARK_INSIDE_LENGTH; 311 this.tickMarkOutsideLength = DEFAULT_TICK_MARK_OUTSIDE_LENGTH; 312 313 this.minorTickMarksVisible = false; 314 this.minorTickMarkInsideLength = 0.0f; 315 this.minorTickMarkOutsideLength = 2.0f; 316 317 this.plot = null; 318 319 this.listenerList = new EventListenerList(); 320 321 } 322 323 /** 324 * Returns <code>true</code> if the axis is visible, and 325 * <code>false</code> otherwise. 326 * 327 * @return A boolean. 328 * 329 * @see #setVisible(boolean) 330 */ 331 public boolean isVisible() { 332 return this.visible; 333 } 334 335 /** 336 * Sets a flag that controls whether or not the axis is visible and sends 337 * an {@link AxisChangeEvent} to all registered listeners. 338 * 339 * @param flag the flag. 340 * 341 * @see #isVisible() 342 */ 343 public void setVisible(boolean flag) { 344 if (flag != this.visible) { 345 this.visible = flag; 346 fireChangeEvent(); 347 } 348 } 349 350 /** 351 * Returns the label for the axis. 352 * 353 * @return The label for the axis (<code>null</code> possible). 354 * 355 * @see #getLabelFont() 356 * @see #getLabelPaint() 357 * @see #setLabel(String) 358 */ 359 public String getLabel() { 360 return this.label; 361 } 362 363 /** 364 * Sets the label for the axis and sends an {@link AxisChangeEvent} to all 365 * registered listeners. 366 * 367 * @param label the new label (<code>null</code> permitted). 368 * 369 * @see #getLabel() 370 * @see #setLabelFont(Font) 371 * @see #setLabelPaint(Paint) 372 */ 373 public void setLabel(String label) { 374 375 String existing = this.label; 376 if (existing != null) { 377 if (!existing.equals(label)) { 378 this.label = label; 379 fireChangeEvent(); 380 } 381 } 382 else { 383 if (label != null) { 384 this.label = label; 385 fireChangeEvent(); 386 } 387 } 388 389 } 390 391 /** 392 * Returns the font for the axis label. 393 * 394 * @return The font (never <code>null</code>). 395 * 396 * @see #setLabelFont(Font) 397 */ 398 public Font getLabelFont() { 399 return this.labelFont; 400 } 401 402 /** 403 * Sets the font for the axis label and sends an {@link AxisChangeEvent} 404 * to all registered listeners. 405 * 406 * @param font the font (<code>null</code> not permitted). 407 * 408 * @see #getLabelFont() 409 */ 410 public void setLabelFont(Font font) { 411 if (font == null) { 412 throw new IllegalArgumentException("Null 'font' argument."); 413 } 414 if (!this.labelFont.equals(font)) { 415 this.labelFont = font; 416 fireChangeEvent(); 417 } 418 } 419 420 /** 421 * Returns the color/shade used to draw the axis label. 422 * 423 * @return The paint (never <code>null</code>). 424 * 425 * @see #setLabelPaint(Paint) 426 */ 427 public Paint getLabelPaint() { 428 return this.labelPaint; 429 } 430 431 /** 432 * Sets the paint used to draw the axis label and sends an 433 * {@link AxisChangeEvent} to all registered listeners. 434 * 435 * @param paint the paint (<code>null</code> not permitted). 436 * 437 * @see #getLabelPaint() 438 */ 439 public void setLabelPaint(Paint paint) { 440 if (paint == null) { 441 throw new IllegalArgumentException("Null 'paint' argument."); 442 } 443 this.labelPaint = paint; 444 fireChangeEvent(); 445 } 446 447 /** 448 * Returns the insets for the label (that is, the amount of blank space 449 * that should be left around the label). 450 * 451 * @return The label insets (never <code>null</code>). 452 * 453 * @see #setLabelInsets(RectangleInsets) 454 */ 455 public RectangleInsets getLabelInsets() { 456 return this.labelInsets; 457 } 458 459 /** 460 * Sets the insets for the axis label, and sends an {@link AxisChangeEvent} 461 * to all registered listeners. 462 * 463 * @param insets the insets (<code>null</code> not permitted). 464 * 465 * @see #getLabelInsets() 466 */ 467 public void setLabelInsets(RectangleInsets insets) { 468 setLabelInsets(insets, true); 469 } 470 471 /** 472 * Sets the insets for the axis label, and sends an {@link AxisChangeEvent} 473 * to all registered listeners. 474 * 475 * @param insets the insets (<code>null</code> not permitted). 476 * @param notify notify listeners? 477 * 478 * @since 1.0.10 479 */ 480 public void setLabelInsets(RectangleInsets insets, boolean notify) { 481 if (insets == null) { 482 throw new IllegalArgumentException("Null 'insets' argument."); 483 } 484 if (!insets.equals(this.labelInsets)) { 485 this.labelInsets = insets; 486 if (notify) { 487 fireChangeEvent(); 488 } 489 } 490 } 491 492 /** 493 * Returns the angle of the axis label. 494 * 495 * @return The angle (in radians). 496 * 497 * @see #setLabelAngle(double) 498 */ 499 public double getLabelAngle() { 500 return this.labelAngle; 501 } 502 503 /** 504 * Sets the angle for the label and sends an {@link AxisChangeEvent} to all 505 * registered listeners. 506 * 507 * @param angle the angle (in radians). 508 * 509 * @see #getLabelAngle() 510 */ 511 public void setLabelAngle(double angle) { 512 this.labelAngle = angle; 513 fireChangeEvent(); 514 } 515 516 /** 517 * A flag that controls whether or not the axis line is drawn. 518 * 519 * @return A boolean. 520 * 521 * @see #getAxisLinePaint() 522 * @see #getAxisLineStroke() 523 * @see #setAxisLineVisible(boolean) 524 */ 525 public boolean isAxisLineVisible() { 526 return this.axisLineVisible; 527 } 528 529 /** 530 * Sets a flag that controls whether or not the axis line is visible and 531 * sends an {@link AxisChangeEvent} to all registered listeners. 532 * 533 * @param visible the flag. 534 * 535 * @see #isAxisLineVisible() 536 * @see #setAxisLinePaint(Paint) 537 * @see #setAxisLineStroke(Stroke) 538 */ 539 public void setAxisLineVisible(boolean visible) { 540 this.axisLineVisible = visible; 541 fireChangeEvent(); 542 } 543 544 /** 545 * Returns the paint used to draw the axis line. 546 * 547 * @return The paint (never <code>null</code>). 548 * 549 * @see #setAxisLinePaint(Paint) 550 */ 551 public Paint getAxisLinePaint() { 552 return this.axisLinePaint; 553 } 554 555 /** 556 * Sets the paint used to draw the axis line and sends an 557 * {@link AxisChangeEvent} to all registered listeners. 558 * 559 * @param paint the paint (<code>null</code> not permitted). 560 * 561 * @see #getAxisLinePaint() 562 */ 563 public void setAxisLinePaint(Paint paint) { 564 if (paint == null) { 565 throw new IllegalArgumentException("Null 'paint' argument."); 566 } 567 this.axisLinePaint = paint; 568 fireChangeEvent(); 569 } 570 571 /** 572 * Returns the stroke used to draw the axis line. 573 * 574 * @return The stroke (never <code>null</code>). 575 * 576 * @see #setAxisLineStroke(Stroke) 577 */ 578 public Stroke getAxisLineStroke() { 579 return this.axisLineStroke; 580 } 581 582 /** 583 * Sets the stroke used to draw the axis line and sends an 584 * {@link AxisChangeEvent} to all registered listeners. 585 * 586 * @param stroke the stroke (<code>null</code> not permitted). 587 * 588 * @see #getAxisLineStroke() 589 */ 590 public void setAxisLineStroke(Stroke stroke) { 591 if (stroke == null) { 592 throw new IllegalArgumentException("Null 'stroke' argument."); 593 } 594 this.axisLineStroke = stroke; 595 fireChangeEvent(); 596 } 597 598 /** 599 * Returns a flag indicating whether or not the tick labels are visible. 600 * 601 * @return The flag. 602 * 603 * @see #getTickLabelFont() 604 * @see #getTickLabelPaint() 605 * @see #setTickLabelsVisible(boolean) 606 */ 607 public boolean isTickLabelsVisible() { 608 return this.tickLabelsVisible; 609 } 610 611 /** 612 * Sets the flag that determines whether or not the tick labels are 613 * visible and sends an {@link AxisChangeEvent} to all registered 614 * listeners. 615 * 616 * @param flag the flag. 617 * 618 * @see #isTickLabelsVisible() 619 * @see #setTickLabelFont(Font) 620 * @see #setTickLabelPaint(Paint) 621 */ 622 public void setTickLabelsVisible(boolean flag) { 623 624 if (flag != this.tickLabelsVisible) { 625 this.tickLabelsVisible = flag; 626 fireChangeEvent(); 627 } 628 629 } 630 631 /** 632 * Returns the flag that indicates whether or not the minor tick marks are 633 * showing. 634 * 635 * @return The flag that indicates whether or not the minor tick marks are 636 * showing. 637 * 638 * @see #setMinorTickMarksVisible(boolean) 639 * 640 * @since 1.0.12 641 */ 642 public boolean isMinorTickMarksVisible() { 643 return this.minorTickMarksVisible; 644 } 645 646 /** 647 * Sets the flag that indicates whether or not the minor tick marks are showing 648 * and sends an {@link AxisChangeEvent} to all registered listeners. 649 * 650 * @param flag the flag. 651 * 652 * @see #isMinorTickMarksVisible() 653 * 654 * @since 1.0.12 655 */ 656 public void setMinorTickMarksVisible(boolean flag) { 657 if (flag != this.minorTickMarksVisible) { 658 this.minorTickMarksVisible = flag; 659 fireChangeEvent(); 660 } 661 } 662 663 /** 664 * Returns the font used for the tick labels (if showing). 665 * 666 * @return The font (never <code>null</code>). 667 * 668 * @see #setTickLabelFont(Font) 669 */ 670 public Font getTickLabelFont() { 671 return this.tickLabelFont; 672 } 673 674 /** 675 * Sets the font for the tick labels and sends an {@link AxisChangeEvent} 676 * to all registered listeners. 677 * 678 * @param font the font (<code>null</code> not allowed). 679 * 680 * @see #getTickLabelFont() 681 */ 682 public void setTickLabelFont(Font font) { 683 684 if (font == null) { 685 throw new IllegalArgumentException("Null 'font' argument."); 686 } 687 688 if (!this.tickLabelFont.equals(font)) { 689 this.tickLabelFont = font; 690 fireChangeEvent(); 691 } 692 693 } 694 695 /** 696 * Returns the color/shade used for the tick labels. 697 * 698 * @return The paint used for the tick labels. 699 * 700 * @see #setTickLabelPaint(Paint) 701 */ 702 public Paint getTickLabelPaint() { 703 return this.tickLabelPaint; 704 } 705 706 /** 707 * Sets the paint used to draw tick labels (if they are showing) and 708 * sends an {@link AxisChangeEvent} to all registered listeners. 709 * 710 * @param paint the paint (<code>null</code> not permitted). 711 * 712 * @see #getTickLabelPaint() 713 */ 714 public void setTickLabelPaint(Paint paint) { 715 if (paint == null) { 716 throw new IllegalArgumentException("Null 'paint' argument."); 717 } 718 this.tickLabelPaint = paint; 719 fireChangeEvent(); 720 } 721 722 /** 723 * Returns the insets for the tick labels. 724 * 725 * @return The insets (never <code>null</code>). 726 * 727 * @see #setTickLabelInsets(RectangleInsets) 728 */ 729 public RectangleInsets getTickLabelInsets() { 730 return this.tickLabelInsets; 731 } 732 733 /** 734 * Sets the insets for the tick labels and sends an {@link AxisChangeEvent} 735 * to all registered listeners. 736 * 737 * @param insets the insets (<code>null</code> not permitted). 738 * 739 * @see #getTickLabelInsets() 740 */ 741 public void setTickLabelInsets(RectangleInsets insets) { 742 if (insets == null) { 743 throw new IllegalArgumentException("Null 'insets' argument."); 744 } 745 if (!this.tickLabelInsets.equals(insets)) { 746 this.tickLabelInsets = insets; 747 fireChangeEvent(); 748 } 749 } 750 751 /** 752 * Returns the flag that indicates whether or not the tick marks are 753 * showing. 754 * 755 * @return The flag that indicates whether or not the tick marks are 756 * showing. 757 * 758 * @see #setTickMarksVisible(boolean) 759 */ 760 public boolean isTickMarksVisible() { 761 return this.tickMarksVisible; 762 } 763 764 /** 765 * Sets the flag that indicates whether or not the tick marks are showing 766 * and sends an {@link AxisChangeEvent} to all registered listeners. 767 * 768 * @param flag the flag. 769 * 770 * @see #isTickMarksVisible() 771 */ 772 public void setTickMarksVisible(boolean flag) { 773 if (flag != this.tickMarksVisible) { 774 this.tickMarksVisible = flag; 775 fireChangeEvent(); 776 } 777 } 778 779 /** 780 * Returns the inside length of the tick marks. 781 * 782 * @return The length. 783 * 784 * @see #getTickMarkOutsideLength() 785 * @see #setTickMarkInsideLength(float) 786 */ 787 public float getTickMarkInsideLength() { 788 return this.tickMarkInsideLength; 789 } 790 791 /** 792 * Sets the inside length of the tick marks and sends 793 * an {@link AxisChangeEvent} to all registered listeners. 794 * 795 * @param length the new length. 796 * 797 * @see #getTickMarkInsideLength() 798 */ 799 public void setTickMarkInsideLength(float length) { 800 this.tickMarkInsideLength = length; 801 fireChangeEvent(); 802 } 803 804 /** 805 * Returns the outside length of the tick marks. 806 * 807 * @return The length. 808 * 809 * @see #getTickMarkInsideLength() 810 * @see #setTickMarkOutsideLength(float) 811 */ 812 public float getTickMarkOutsideLength() { 813 return this.tickMarkOutsideLength; 814 } 815 816 /** 817 * Sets the outside length of the tick marks and sends 818 * an {@link AxisChangeEvent} to all registered listeners. 819 * 820 * @param length the new length. 821 * 822 * @see #getTickMarkInsideLength() 823 */ 824 public void setTickMarkOutsideLength(float length) { 825 this.tickMarkOutsideLength = length; 826 fireChangeEvent(); 827 } 828 829 /** 830 * Returns the stroke used to draw tick marks. 831 * 832 * @return The stroke (never <code>null</code>). 833 * 834 * @see #setTickMarkStroke(Stroke) 835 */ 836 public Stroke getTickMarkStroke() { 837 return this.tickMarkStroke; 838 } 839 840 /** 841 * Sets the stroke used to draw tick marks and sends 842 * an {@link AxisChangeEvent} to all registered listeners. 843 * 844 * @param stroke the stroke (<code>null</code> not permitted). 845 * 846 * @see #getTickMarkStroke() 847 */ 848 public void setTickMarkStroke(Stroke stroke) { 849 if (stroke == null) { 850 throw new IllegalArgumentException("Null 'stroke' argument."); 851 } 852 if (!this.tickMarkStroke.equals(stroke)) { 853 this.tickMarkStroke = stroke; 854 fireChangeEvent(); 855 } 856 } 857 858 /** 859 * Returns the paint used to draw tick marks (if they are showing). 860 * 861 * @return The paint (never <code>null</code>). 862 * 863 * @see #setTickMarkPaint(Paint) 864 */ 865 public Paint getTickMarkPaint() { 866 return this.tickMarkPaint; 867 } 868 869 /** 870 * Sets the paint used to draw tick marks and sends an 871 * {@link AxisChangeEvent} to all registered listeners. 872 * 873 * @param paint the paint (<code>null</code> not permitted). 874 * 875 * @see #getTickMarkPaint() 876 */ 877 public void setTickMarkPaint(Paint paint) { 878 if (paint == null) { 879 throw new IllegalArgumentException("Null 'paint' argument."); 880 } 881 this.tickMarkPaint = paint; 882 fireChangeEvent(); 883 } 884 885 /** 886 * Returns the inside length of the minor tick marks. 887 * 888 * @return The length. 889 * 890 * @see #getMinorTickMarkOutsideLength() 891 * @see #setMinorTickMarkInsideLength(float) 892 * 893 * @since 1.0.12 894 */ 895 public float getMinorTickMarkInsideLength() { 896 return this.minorTickMarkInsideLength; 897 } 898 899 /** 900 * Sets the inside length of the minor tick marks and sends 901 * an {@link AxisChangeEvent} to all registered listeners. 902 * 903 * @param length the new length. 904 * 905 * @see #getMinorTickMarkInsideLength() 906 * 907 * @since 1.0.12 908 */ 909 public void setMinorTickMarkInsideLength(float length) { 910 this.minorTickMarkInsideLength = length; 911 fireChangeEvent(); 912 } 913 914 /** 915 * Returns the outside length of the minor tick marks. 916 * 917 * @return The length. 918 * 919 * @see #getMinorTickMarkInsideLength() 920 * @see #setMinorTickMarkOutsideLength(float) 921 * 922 * @since 1.0.12 923 */ 924 public float getMinorTickMarkOutsideLength() { 925 return this.minorTickMarkOutsideLength; 926 } 927 928 /** 929 * Sets the outside length of the minor tick marks and sends 930 * an {@link AxisChangeEvent} to all registered listeners. 931 * 932 * @param length the new length. 933 * 934 * @see #getMinorTickMarkInsideLength() 935 * 936 * @since 1.0.12 937 */ 938 public void setMinorTickMarkOutsideLength(float length) { 939 this.minorTickMarkOutsideLength = length; 940 fireChangeEvent(); 941 } 942 943 /** 944 * Returns the plot that the axis is assigned to. This method will return 945 * <code>null</code> if the axis is not currently assigned to a plot. 946 * 947 * @return The plot that the axis is assigned to (possibly 948 * <code>null</code>). 949 * 950 * @see #setPlot(Plot) 951 */ 952 public Plot getPlot() { 953 return this.plot; 954 } 955 956 /** 957 * Sets a reference to the plot that the axis is assigned to. 958 * <P> 959 * This method is used internally, you shouldn't need to call it yourself. 960 * 961 * @param plot the plot. 962 * 963 * @see #getPlot() 964 */ 965 public void setPlot(Plot plot) { 966 this.plot = plot; 967 configure(); 968 } 969 970 /** 971 * Returns the fixed dimension for the axis. 972 * 973 * @return The fixed dimension. 974 * 975 * @see #setFixedDimension(double) 976 */ 977 public double getFixedDimension() { 978 return this.fixedDimension; 979 } 980 981 /** 982 * Sets the fixed dimension for the axis. 983 * <P> 984 * This is used when combining more than one plot on a chart. In this case, 985 * there may be several axes that need to have the same height or width so 986 * that they are aligned. This method is used to fix a dimension for the 987 * axis (the context determines whether the dimension is horizontal or 988 * vertical). 989 * 990 * @param dimension the fixed dimension. 991 * 992 * @see #getFixedDimension() 993 */ 994 public void setFixedDimension(double dimension) { 995 this.fixedDimension = dimension; 996 } 997 998 /** 999 * Configures the axis to work with the current plot. Override this method 1000 * to perform any special processing (such as auto-rescaling). 1001 */ 1002 public abstract void configure(); 1003 1004 /** 1005 * Estimates the space (height or width) required to draw the axis. 1006 * 1007 * @param g2 the graphics device. 1008 * @param plot the plot that the axis belongs to. 1009 * @param plotArea the area within which the plot (including axes) should 1010 * be drawn. 1011 * @param edge the axis location. 1012 * @param space space already reserved. 1013 * 1014 * @return The space required to draw the axis (including pre-reserved 1015 * space). 1016 */ 1017 public abstract AxisSpace reserveSpace(Graphics2D g2, Plot plot, 1018 Rectangle2D plotArea, 1019 RectangleEdge edge, 1020 AxisSpace space); 1021 1022 /** 1023 * Draws the axis on a Java 2D graphics device (such as the screen or a 1024 * printer). 1025 * 1026 * @param g2 the graphics device (<code>null</code> not permitted). 1027 * @param cursor the cursor location (determines where to draw the axis). 1028 * @param plotArea the area within which the axes and plot should be drawn. 1029 * @param dataArea the area within which the data should be drawn. 1030 * @param edge the axis location (<code>null</code> not permitted). 1031 * @param plotState collects information about the plot 1032 * (<code>null</code> permitted). 1033 * 1034 * @return The axis state (never <code>null</code>). 1035 */ 1036 public abstract AxisState draw(Graphics2D g2, 1037 double cursor, 1038 Rectangle2D plotArea, 1039 Rectangle2D dataArea, 1040 RectangleEdge edge, 1041 PlotRenderingInfo plotState); 1042 1043 /** 1044 * Calculates the positions of the ticks for the axis, storing the results 1045 * in the tick list (ready for drawing). 1046 * 1047 * @param g2 the graphics device. 1048 * @param state the axis state. 1049 * @param dataArea the area inside the axes. 1050 * @param edge the edge on which the axis is located. 1051 * 1052 * @return The list of ticks. 1053 */ 1054 public abstract List refreshTicks(Graphics2D g2, AxisState state, 1055 Rectangle2D dataArea, RectangleEdge edge); 1056 1057 /** 1058 * Created an entity for the axis. 1059 * 1060 * @param cursor the initial cursor value. 1061 * @param state the axis state after completion of the drawing with a 1062 * possibly updated cursor position. 1063 * @param dataArea the data area. 1064 * @param edge the edge. 1065 * @param plotState the PlotRenderingInfo from which a reference to the 1066 * entity collection can be obtained. 1067 * 1068 * @since 1.0.13 1069 */ 1070 protected void createAndAddEntity(double cursor, AxisState state, 1071 Rectangle2D dataArea, RectangleEdge edge, 1072 PlotRenderingInfo plotState){ 1073 1074 if (plotState == null || plotState.getOwner() == null) { 1075 return; // no need to create entity if we canĀ“t save it anyways... 1076 } 1077 Rectangle2D hotspot = null; 1078 if (edge.equals(RectangleEdge.TOP)){ 1079 hotspot = new Rectangle2D.Double(dataArea.getX(), 1080 state.getCursor(), dataArea.getWidth(), 1081 cursor - state.getCursor()); 1082 } 1083 else if(edge.equals(RectangleEdge.BOTTOM)) { 1084 hotspot = new Rectangle2D.Double(dataArea.getX(), cursor, 1085 dataArea.getWidth(), state.getCursor() - cursor); 1086 } 1087 else if(edge.equals(RectangleEdge.LEFT)) { 1088 hotspot = new Rectangle2D.Double(state.getCursor(), 1089 dataArea.getY(), cursor - state.getCursor(), 1090 dataArea.getHeight()); 1091 } 1092 else if(edge.equals(RectangleEdge.RIGHT)){ 1093 hotspot = new Rectangle2D.Double(cursor, dataArea.getY(), 1094 state.getCursor() - cursor, dataArea.getHeight()); 1095 } 1096 EntityCollection e = plotState.getOwner().getEntityCollection(); 1097 if (e != null) { 1098 e.add(new AxisEntity(hotspot, this)); 1099 } 1100 } 1101 1102 /** 1103 * Registers an object for notification of changes to the axis. 1104 * 1105 * @param listener the object that is being registered. 1106 * 1107 * @see #removeChangeListener(AxisChangeListener) 1108 */ 1109 public void addChangeListener(AxisChangeListener listener) { 1110 this.listenerList.add(AxisChangeListener.class, listener); 1111 } 1112 1113 /** 1114 * Deregisters an object for notification of changes to the axis. 1115 * 1116 * @param listener the object to deregister. 1117 * 1118 * @see #addChangeListener(AxisChangeListener) 1119 */ 1120 public void removeChangeListener(AxisChangeListener listener) { 1121 this.listenerList.remove(AxisChangeListener.class, listener); 1122 } 1123 1124 /** 1125 * Returns <code>true</code> if the specified object is registered with 1126 * the dataset as a listener. Most applications won't need to call this 1127 * method, it exists mainly for use by unit testing code. 1128 * 1129 * @param listener the listener. 1130 * 1131 * @return A boolean. 1132 */ 1133 public boolean hasListener(EventListener listener) { 1134 List list = Arrays.asList(this.listenerList.getListenerList()); 1135 return list.contains(listener); 1136 } 1137 1138 /** 1139 * Notifies all registered listeners that the axis has changed. 1140 * The AxisChangeEvent provides information about the change. 1141 * 1142 * @param event information about the change to the axis. 1143 */ 1144 protected void notifyListeners(AxisChangeEvent event) { 1145 Object[] listeners = this.listenerList.getListenerList(); 1146 for (int i = listeners.length - 2; i >= 0; i -= 2) { 1147 if (listeners[i] == AxisChangeListener.class) { 1148 ((AxisChangeListener) listeners[i + 1]).axisChanged(event); 1149 } 1150 } 1151 } 1152 1153 /** 1154 * Sends an {@link AxisChangeEvent} to all registered listeners. 1155 * 1156 * @since 1.0.12 1157 */ 1158 protected void fireChangeEvent() { 1159 notifyListeners(new AxisChangeEvent(this)); 1160 } 1161 1162 /** 1163 * Returns a rectangle that encloses the axis label. This is typically 1164 * used for layout purposes (it gives the maximum dimensions of the label). 1165 * 1166 * @param g2 the graphics device. 1167 * @param edge the edge of the plot area along which the axis is measuring. 1168 * 1169 * @return The enclosing rectangle. 1170 */ 1171 protected Rectangle2D getLabelEnclosure(Graphics2D g2, RectangleEdge edge) { 1172 1173 Rectangle2D result = new Rectangle2D.Double(); 1174 String axisLabel = getLabel(); 1175 if (axisLabel != null && !axisLabel.equals("")) { 1176 FontMetrics fm = g2.getFontMetrics(getLabelFont()); 1177 Rectangle2D bounds = TextUtilities.getTextBounds(axisLabel, g2, fm); 1178 RectangleInsets insets = getLabelInsets(); 1179 bounds = insets.createOutsetRectangle(bounds); 1180 double angle = getLabelAngle(); 1181 if (edge == RectangleEdge.LEFT || edge == RectangleEdge.RIGHT) { 1182 angle = angle - Math.PI / 2.0; 1183 } 1184 double x = bounds.getCenterX(); 1185 double y = bounds.getCenterY(); 1186 AffineTransform transformer 1187 = AffineTransform.getRotateInstance(angle, x, y); 1188 Shape labelBounds = transformer.createTransformedShape(bounds); 1189 result = labelBounds.getBounds2D(); 1190 } 1191 1192 return result; 1193 1194 } 1195 1196 /** 1197 * Draws the axis label. 1198 * 1199 * @param label the label text. 1200 * @param g2 the graphics device. 1201 * @param plotArea the plot area. 1202 * @param dataArea the area inside the axes. 1203 * @param edge the location of the axis. 1204 * @param state the axis state (<code>null</code> not permitted). 1205 * 1206 * @return Information about the axis. 1207 */ 1208 protected AxisState drawLabel(String label, Graphics2D g2, 1209 Rectangle2D plotArea, Rectangle2D dataArea, RectangleEdge edge, 1210 AxisState state) { 1211 1212 // it is unlikely that 'state' will be null, but check anyway... 1213 if (state == null) { 1214 throw new IllegalArgumentException("Null 'state' argument."); 1215 } 1216 1217 if ((label == null) || (label.equals(""))) { 1218 return state; 1219 } 1220 1221 Font font = getLabelFont(); 1222 RectangleInsets insets = getLabelInsets(); 1223 g2.setFont(font); 1224 g2.setPaint(getLabelPaint()); 1225 FontMetrics fm = g2.getFontMetrics(); 1226 Rectangle2D labelBounds = TextUtilities.getTextBounds(label, g2, fm); 1227 1228 if (edge == RectangleEdge.TOP) { 1229 AffineTransform t = AffineTransform.getRotateInstance( 1230 getLabelAngle(), labelBounds.getCenterX(), 1231 labelBounds.getCenterY()); 1232 Shape rotatedLabelBounds = t.createTransformedShape(labelBounds); 1233 labelBounds = rotatedLabelBounds.getBounds2D(); 1234 double labelx = dataArea.getCenterX(); 1235 double labely = state.getCursor() - insets.getBottom() 1236 - labelBounds.getHeight() / 2.0; 1237 TextUtilities.drawRotatedString(label, g2, (float) labelx, 1238 (float) labely, TextAnchor.CENTER, getLabelAngle(), 1239 TextAnchor.CENTER); 1240 state.cursorUp(insets.getTop() + labelBounds.getHeight() 1241 + insets.getBottom()); 1242 } 1243 else if (edge == RectangleEdge.BOTTOM) { 1244 AffineTransform t = AffineTransform.getRotateInstance( 1245 getLabelAngle(), labelBounds.getCenterX(), 1246 labelBounds.getCenterY()); 1247 Shape rotatedLabelBounds = t.createTransformedShape(labelBounds); 1248 labelBounds = rotatedLabelBounds.getBounds2D(); 1249 double labelx = dataArea.getCenterX(); 1250 double labely = state.getCursor() 1251 + insets.getTop() + labelBounds.getHeight() / 2.0; 1252 TextUtilities.drawRotatedString(label, g2, (float) labelx, 1253 (float) labely, TextAnchor.CENTER, getLabelAngle(), 1254 TextAnchor.CENTER); 1255 state.cursorDown(insets.getTop() + labelBounds.getHeight() 1256 + insets.getBottom()); 1257 } 1258 else if (edge == RectangleEdge.LEFT) { 1259 AffineTransform t = AffineTransform.getRotateInstance( 1260 getLabelAngle() - Math.PI / 2.0, labelBounds.getCenterX(), 1261 labelBounds.getCenterY()); 1262 Shape rotatedLabelBounds = t.createTransformedShape(labelBounds); 1263 labelBounds = rotatedLabelBounds.getBounds2D(); 1264 double labelx = state.getCursor() 1265 - insets.getRight() - labelBounds.getWidth() / 2.0; 1266 double labely = dataArea.getCenterY(); 1267 TextUtilities.drawRotatedString(label, g2, (float) labelx, 1268 (float) labely, TextAnchor.CENTER, 1269 getLabelAngle() - Math.PI / 2.0, TextAnchor.CENTER); 1270 state.cursorLeft(insets.getLeft() + labelBounds.getWidth() 1271 + insets.getRight()); 1272 } 1273 else if (edge == RectangleEdge.RIGHT) { 1274 1275 AffineTransform t = AffineTransform.getRotateInstance( 1276 getLabelAngle() + Math.PI / 2.0, 1277 labelBounds.getCenterX(), labelBounds.getCenterY()); 1278 Shape rotatedLabelBounds = t.createTransformedShape(labelBounds); 1279 labelBounds = rotatedLabelBounds.getBounds2D(); 1280 double labelx = state.getCursor() 1281 + insets.getLeft() + labelBounds.getWidth() / 2.0; 1282 double labely = dataArea.getY() + dataArea.getHeight() / 2.0; 1283 TextUtilities.drawRotatedString(label, g2, (float) labelx, 1284 (float) labely, TextAnchor.CENTER, 1285 getLabelAngle() + Math.PI / 2.0, TextAnchor.CENTER); 1286 state.cursorRight(insets.getLeft() + labelBounds.getWidth() 1287 + insets.getRight()); 1288 1289 } 1290 1291 return state; 1292 1293 } 1294 1295 /** 1296 * Draws an axis line at the current cursor position and edge. 1297 * 1298 * @param g2 the graphics device. 1299 * @param cursor the cursor position. 1300 * @param dataArea the data area. 1301 * @param edge the edge. 1302 */ 1303 protected void drawAxisLine(Graphics2D g2, double cursor, 1304 Rectangle2D dataArea, RectangleEdge edge) { 1305 1306 Line2D axisLine = null; 1307 if (edge == RectangleEdge.TOP) { 1308 axisLine = new Line2D.Double(dataArea.getX(), cursor, 1309 dataArea.getMaxX(), cursor); 1310 } 1311 else if (edge == RectangleEdge.BOTTOM) { 1312 axisLine = new Line2D.Double(dataArea.getX(), cursor, 1313 dataArea.getMaxX(), cursor); 1314 } 1315 else if (edge == RectangleEdge.LEFT) { 1316 axisLine = new Line2D.Double(cursor, dataArea.getY(), cursor, 1317 dataArea.getMaxY()); 1318 } 1319 else if (edge == RectangleEdge.RIGHT) { 1320 axisLine = new Line2D.Double(cursor, dataArea.getY(), cursor, 1321 dataArea.getMaxY()); 1322 } 1323 g2.setPaint(this.axisLinePaint); 1324 g2.setStroke(this.axisLineStroke); 1325 g2.draw(axisLine); 1326 1327 } 1328 1329 /** 1330 * Returns a clone of the axis. 1331 * 1332 * @return A clone. 1333 * 1334 * @throws CloneNotSupportedException if some component of the axis does 1335 * not support cloning. 1336 */ 1337 public Object clone() throws CloneNotSupportedException { 1338 Axis clone = (Axis) super.clone(); 1339 // It's up to the plot which clones up to restore the correct references 1340 clone.plot = null; 1341 clone.listenerList = new EventListenerList(); 1342 return clone; 1343 } 1344 1345 /** 1346 * Tests this axis for equality with another object. 1347 * 1348 * @param obj the object (<code>null</code> permitted). 1349 * 1350 * @return <code>true</code> or <code>false</code>. 1351 */ 1352 public boolean equals(Object obj) { 1353 if (obj == this) { 1354 return true; 1355 } 1356 if (!(obj instanceof Axis)) { 1357 return false; 1358 } 1359 Axis that = (Axis) obj; 1360 if (this.visible != that.visible) { 1361 return false; 1362 } 1363 if (!ObjectUtilities.equal(this.label, that.label)) { 1364 return false; 1365 } 1366 if (!ObjectUtilities.equal(this.labelFont, that.labelFont)) { 1367 return false; 1368 } 1369 if (!PaintUtilities.equal(this.labelPaint, that.labelPaint)) { 1370 return false; 1371 } 1372 if (!ObjectUtilities.equal(this.labelInsets, that.labelInsets)) { 1373 return false; 1374 } 1375 if (this.labelAngle != that.labelAngle) { 1376 return false; 1377 } 1378 if (this.axisLineVisible != that.axisLineVisible) { 1379 return false; 1380 } 1381 if (!ObjectUtilities.equal(this.axisLineStroke, that.axisLineStroke)) { 1382 return false; 1383 } 1384 if (!PaintUtilities.equal(this.axisLinePaint, that.axisLinePaint)) { 1385 return false; 1386 } 1387 if (this.tickLabelsVisible != that.tickLabelsVisible) { 1388 return false; 1389 } 1390 if (!ObjectUtilities.equal(this.tickLabelFont, that.tickLabelFont)) { 1391 return false; 1392 } 1393 if (!PaintUtilities.equal(this.tickLabelPaint, that.tickLabelPaint)) { 1394 return false; 1395 } 1396 if (!ObjectUtilities.equal( 1397 this.tickLabelInsets, that.tickLabelInsets 1398 )) { 1399 return false; 1400 } 1401 if (this.tickMarksVisible != that.tickMarksVisible) { 1402 return false; 1403 } 1404 if (this.tickMarkInsideLength != that.tickMarkInsideLength) { 1405 return false; 1406 } 1407 if (this.tickMarkOutsideLength != that.tickMarkOutsideLength) { 1408 return false; 1409 } 1410 if (!PaintUtilities.equal(this.tickMarkPaint, that.tickMarkPaint)) { 1411 return false; 1412 } 1413 if (!ObjectUtilities.equal(this.tickMarkStroke, that.tickMarkStroke)) { 1414 return false; 1415 } 1416 if (this.minorTickMarksVisible != that.minorTickMarksVisible) { 1417 return false; 1418 } 1419 if (this.minorTickMarkInsideLength != that.minorTickMarkInsideLength) { 1420 return false; 1421 } 1422 if (this.minorTickMarkOutsideLength != that.minorTickMarkOutsideLength) { 1423 return false; 1424 } 1425 if (this.fixedDimension != that.fixedDimension) { 1426 return false; 1427 } 1428 return true; 1429 } 1430 1431 /** 1432 * Provides serialization support. 1433 * 1434 * @param stream the output stream. 1435 * 1436 * @throws IOException if there is an I/O error. 1437 */ 1438 private void writeObject(ObjectOutputStream stream) throws IOException { 1439 stream.defaultWriteObject(); 1440 SerialUtilities.writePaint(this.labelPaint, stream); 1441 SerialUtilities.writePaint(this.tickLabelPaint, stream); 1442 SerialUtilities.writeStroke(this.axisLineStroke, stream); 1443 SerialUtilities.writePaint(this.axisLinePaint, stream); 1444 SerialUtilities.writeStroke(this.tickMarkStroke, stream); 1445 SerialUtilities.writePaint(this.tickMarkPaint, stream); 1446 } 1447 1448 /** 1449 * Provides serialization support. 1450 * 1451 * @param stream the input stream. 1452 * 1453 * @throws IOException if there is an I/O error. 1454 * @throws ClassNotFoundException if there is a classpath problem. 1455 */ 1456 private void readObject(ObjectInputStream stream) 1457 throws IOException, ClassNotFoundException { 1458 stream.defaultReadObject(); 1459 this.labelPaint = SerialUtilities.readPaint(stream); 1460 this.tickLabelPaint = SerialUtilities.readPaint(stream); 1461 this.axisLineStroke = SerialUtilities.readStroke(stream); 1462 this.axisLinePaint = SerialUtilities.readPaint(stream); 1463 this.tickMarkStroke = SerialUtilities.readStroke(stream); 1464 this.tickMarkPaint = SerialUtilities.readPaint(stream); 1465 this.listenerList = new EventListenerList(); 1466 } 1467 1468 }