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