Source for org.jfree.chart.axis.Axis

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