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