Source for org.jfree.chart.plot.Marker

   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:  * Marker.java
  29:  * -----------
  30:  * (C) Copyright 2002-2006, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   Nicolas Brodu;
  34:  *
  35:  * $Id: Marker.java,v 1.10.2.5 2006/09/05 14:34:23 mungady Exp $
  36:  *
  37:  * Changes (since 2-Jul-2002)
  38:  * --------------------------
  39:  * 02-Jul-2002 : Added extra constructor, standard header and Javadoc 
  40:  *               comments (DG);
  41:  * 20-Aug-2002 : Added the outline stroke attribute (DG);
  42:  * 02-Oct-2002 : Fixed errors reported by Checkstyle (DG);
  43:  * 16-Oct-2002 : Added new constructor (DG);
  44:  * 26-Mar-2003 : Implemented Serializable (DG);
  45:  * 21-May-2003 : Added labels (DG);
  46:  * 11-Sep-2003 : Implemented Cloneable (NB);
  47:  * 05-Nov-2003 : Added checks to ensure some attributes are never null (DG);
  48:  * 11-Feb-2003 : Moved to org.jfree.chart.plot package, plus significant API 
  49:  *               changes to support IntervalMarker in plots (DG);
  50:  * 14-Jun-2004 : Updated equals() method (DG);
  51:  * 21-Jan-2005 : Added settings to control direction of horizontal and 
  52:  *               vertical label offsets (DG);
  53:  * 01-Jun-2005 : Modified to use only one label offset type - this will be 
  54:  *               applied to the domain or range axis as appropriate (DG);
  55:  * 06-Jun-2005 : Fix equals() method to handle GradientPaint (DG);
  56:  * 19-Aug-2005 : Changed constructor from public --> protected (DG);
  57:  * ------------- JFREECHART 1.0.0 ---------------------------------------------
  58:  * 05-Sep-2006 : Added MarkerChangeListener support (DG);
  59:  *
  60:  */
  61: 
  62: package org.jfree.chart.plot;
  63: 
  64: import java.awt.BasicStroke;
  65: import java.awt.Color;
  66: import java.awt.Font;
  67: import java.awt.Paint;
  68: import java.awt.Stroke;
  69: import java.io.IOException;
  70: import java.io.ObjectInputStream;
  71: import java.io.ObjectOutputStream;
  72: import java.io.Serializable;
  73: import java.util.EventListener;
  74: 
  75: import javax.swing.event.EventListenerList;
  76: 
  77: import org.jfree.chart.event.MarkerChangeEvent;
  78: import org.jfree.chart.event.MarkerChangeListener;
  79: import org.jfree.io.SerialUtilities;
  80: import org.jfree.ui.LengthAdjustmentType;
  81: import org.jfree.ui.RectangleAnchor;
  82: import org.jfree.ui.RectangleInsets;
  83: import org.jfree.ui.TextAnchor;
  84: import org.jfree.util.ObjectUtilities;
  85: import org.jfree.util.PaintUtilities;
  86: 
  87: /**
  88:  * The base class for markers that can be added to plots to highlight a value 
  89:  * or range of values.
  90:  * <br><br>
  91:  * An event notification mechanism was added to this class in JFreeChart 
  92:  * version 1.0.3.
  93:  */
  94: public abstract class Marker implements Cloneable, Serializable {
  95: 
  96:     /** For serialization. */
  97:     private static final long serialVersionUID = -734389651405327166L;
  98: 
  99:     /** The paint. */
 100:     private transient Paint paint;
 101: 
 102:     /** The stroke. */
 103:     private transient Stroke stroke;
 104:     
 105:     /** The outline paint. */
 106:     private transient Paint outlinePaint;
 107: 
 108:     /** The outline stroke. */
 109:     private transient Stroke outlineStroke;
 110: 
 111:     /** The alpha transparency. */
 112:     private float alpha;
 113: 
 114:     /** The label. */
 115:     private String label = null;
 116: 
 117:     /** The label font. */
 118:     private Font labelFont;
 119: 
 120:     /** The label paint. */
 121:     private transient Paint labelPaint;
 122: 
 123:     /** The label position. */
 124:     private RectangleAnchor labelAnchor;
 125:     
 126:     /** The text anchor for the label. */
 127:     private TextAnchor labelTextAnchor;
 128: 
 129:     /** The label offset from the marker rectangle. */
 130:     private RectangleInsets labelOffset;
 131:     
 132:     /** 
 133:      * The offset type for the domain or range axis (never <code>null</code>). 
 134:      */
 135:     private LengthAdjustmentType labelOffsetType;
 136:     
 137:     /** Storage for registered change listeners. */
 138:     private transient EventListenerList listenerList;
 139: 
 140:     /**
 141:      * Creates a new marker with default attributes.
 142:      */
 143:     protected Marker() {
 144:         this(Color.gray);
 145:     }
 146: 
 147:     /**
 148:      * Constructs a new marker.
 149:      *
 150:      * @param paint  the paint (<code>null</code> not permitted).
 151:      */
 152:     protected Marker(Paint paint) {
 153:         this(paint, new BasicStroke(0.5f), Color.gray, new BasicStroke(0.5f), 
 154:                 0.80f);
 155:     }
 156: 
 157:     /**
 158:      * Constructs a new marker.
 159:      *
 160:      * @param paint  the paint (<code>null</code> not permitted).
 161:      * @param stroke  the stroke (<code>null</code> not permitted).
 162:      * @param outlinePaint  the outline paint (<code>null</code> permitted).
 163:      * @param outlineStroke  the outline stroke (<code>null</code> permitted).
 164:      * @param alpha  the alpha transparency (must be in the range 0.0f to 
 165:      *     1.0f).
 166:      *     
 167:      * @throws IllegalArgumentException if <code>paint</code> or 
 168:      *     <code>stroke</code> is <code>null</code>, or <code>alpha</code> is 
 169:      *     not in the specified range.
 170:      */
 171:     protected Marker(Paint paint, Stroke stroke, 
 172:                      Paint outlinePaint, Stroke outlineStroke, 
 173:                      float alpha) {
 174: 
 175:         if (paint == null) {
 176:             throw new IllegalArgumentException("Null 'paint' argument.");
 177:         }
 178:         if (stroke == null) {
 179:             throw new IllegalArgumentException("Null 'stroke' argument.");
 180:         }
 181:         if (alpha < 0.0f || alpha > 1.0f)
 182:             throw new IllegalArgumentException(
 183:                     "The 'alpha' value must be in the range 0.0f to 1.0f");
 184:         
 185:         this.paint = paint;
 186:         this.stroke = stroke;
 187:         this.outlinePaint = outlinePaint;
 188:         this.outlineStroke = outlineStroke;
 189:         this.alpha = alpha;
 190:         
 191:         this.labelFont = new Font("SansSerif", Font.PLAIN, 9);
 192:         this.labelPaint = Color.black;
 193:         this.labelAnchor = RectangleAnchor.TOP_LEFT;
 194:         this.labelOffset = new RectangleInsets(3.0, 3.0, 3.0, 3.0);
 195:         this.labelOffsetType = LengthAdjustmentType.CONTRACT;
 196:         this.labelTextAnchor = TextAnchor.CENTER;
 197:         
 198:         this.listenerList = new EventListenerList();
 199:     }
 200: 
 201:     /**
 202:      * Returns the paint.
 203:      *
 204:      * @return The paint (never <code>null</code>).
 205:      * 
 206:      * @see #setPaint(Paint)
 207:      */
 208:     public Paint getPaint() {
 209:         return this.paint;
 210:     }
 211:     
 212:     /**
 213:      * Sets the paint and sends a {@link MarkerChangeEvent} to all registered
 214:      * listeners.
 215:      * 
 216:      * @param paint  the paint (<code>null</code> not permitted).
 217:      * 
 218:      * @see #getPaint()
 219:      */
 220:     public void setPaint(Paint paint) {
 221:         if (paint == null) {
 222:             throw new IllegalArgumentException("Null 'paint' argument.");
 223:         }
 224:         this.paint = paint;
 225:         notifyListeners(new MarkerChangeEvent(this));
 226:     }
 227: 
 228:     /**
 229:      * Returns the stroke.
 230:      *
 231:      * @return The stroke (never <code>null</code>).
 232:      * 
 233:      * @see #setStroke(Stroke)
 234:      */
 235:     public Stroke getStroke() {
 236:         return this.stroke;
 237:     }
 238:     
 239:     /**
 240:      * Sets the stroke and sends a {@link MarkerChangeEvent} to all registered
 241:      * listeners.
 242:      * 
 243:      * @param stroke  the stroke (<code>null</code> not permitted).
 244:      * 
 245:      * @see #getStroke()
 246:      */
 247:     public void setStroke(Stroke stroke) {
 248:         if (stroke == null) {
 249:             throw new IllegalArgumentException("Null 'stroke' argument.");
 250:         }
 251:         this.stroke = stroke;
 252:         notifyListeners(new MarkerChangeEvent(this));
 253:     }
 254: 
 255:     /**
 256:      * Returns the outline paint.
 257:      *
 258:      * @return The outline paint (possibly <code>null</code>).
 259:      * 
 260:      * @see #setOutlinePaint(Paint)
 261:      */
 262:     public Paint getOutlinePaint() {
 263:         return this.outlinePaint;
 264:     }
 265:     
 266:     /**
 267:      * Sets the outline paint and sends a {@link MarkerChangeEvent} to all 
 268:      * registered listeners.
 269:      * 
 270:      * @param paint  the paint (<code>null</code> permitted).
 271:      * 
 272:      * @see #getOutlinePaint()
 273:      */
 274:     public void setOutlinePaint(Paint paint) {
 275:         this.outlinePaint = paint;
 276:         notifyListeners(new MarkerChangeEvent(this));
 277:     }
 278: 
 279:     /**
 280:      * Returns the outline stroke.
 281:      *
 282:      * @return The outline stroke (possibly <code>null</code>).
 283:      * 
 284:      * @see #setOutlineStroke(Stroke)
 285:      */
 286:     public Stroke getOutlineStroke() {
 287:         return this.outlineStroke;
 288:     }
 289:     
 290:     /**
 291:      * Sets the outline stroke and sends a {@link MarkerChangeEvent} to all 
 292:      * registered listeners.
 293:      * 
 294:      * @param stroke  the stroke (<code>null</code> permitted).
 295:      * 
 296:      * @see #getOutlineStroke()
 297:      */
 298:     public void setOutlineStroke(Stroke stroke) {
 299:         this.outlineStroke = stroke;
 300:         notifyListeners(new MarkerChangeEvent(this));
 301:     }
 302: 
 303:     /**
 304:      * Returns the alpha transparency.
 305:      *
 306:      * @return The alpha transparency.
 307:      * 
 308:      * @see #setAlpha(float)
 309:      */
 310:     public float getAlpha() {
 311:         return this.alpha;
 312:     }
 313:     
 314:     /**
 315:      * Sets the alpha transparency that should be used when drawing the 
 316:      * marker, and sends a {@link MarkerChangeEvent} to all registered 
 317:      * listeners.  The alpha transparency is a value in the range 0.0f 
 318:      * (completely transparent) to 1.0f (completely opaque).
 319:      * 
 320:      * @param alpha  the alpha transparency (must be in the range 0.0f to 
 321:      *     1.0f).
 322:      *     
 323:      * @throws IllegalArgumentException if <code>alpha</code> is not in the
 324:      *     specified range.
 325:      *     
 326:      * @see #getAlpha()
 327:      */
 328:     public void setAlpha(float alpha) {
 329:         if (alpha < 0.0f || alpha > 1.0f)
 330:             throw new IllegalArgumentException(
 331:                     "The 'alpha' value must be in the range 0.0f to 1.0f");
 332:         this.alpha = alpha;
 333:         notifyListeners(new MarkerChangeEvent(this));
 334:     }
 335: 
 336:     /**
 337:      * Returns the label (if <code>null</code> no label is displayed).
 338:      *
 339:      * @return The label (possibly <code>null</code>).
 340:      * 
 341:      * @see #setLabel(String)
 342:      */
 343:     public String getLabel() {
 344:         return this.label;
 345:     }
 346: 
 347:     /**
 348:      * Sets the label (if <code>null</code> no label is displayed) and sends a
 349:      * {@link MarkerChangeEvent} to all registered listeners.
 350:      *
 351:      * @param label  the label (<code>null</code> permitted).
 352:      * 
 353:      * @see #getLabel()
 354:      */
 355:     public void setLabel(String label) {
 356:         this.label = label;
 357:         notifyListeners(new MarkerChangeEvent(this));
 358:     }
 359: 
 360:     /**
 361:      * Returns the label font.
 362:      *
 363:      * @return The label font (never <code>null</code>).
 364:      * 
 365:      * @see #setLabelFont(Font)
 366:      */
 367:     public Font getLabelFont() {
 368:         return this.labelFont;
 369:     }
 370: 
 371:     /**
 372:      * Sets the label font and sends a {@link MarkerChangeEvent} to all 
 373:      * registered listeners.
 374:      *
 375:      * @param font  the font (<code>null</code> not permitted).
 376:      * 
 377:      * @see #getLabelFont()
 378:      */
 379:     public void setLabelFont(Font font) {
 380:         if (font == null) {
 381:             throw new IllegalArgumentException("Null 'font' argument.");
 382:         }
 383:         this.labelFont = font;
 384:         notifyListeners(new MarkerChangeEvent(this));
 385:     }
 386: 
 387:     /**
 388:      * Returns the label paint.
 389:      *
 390:      * @return The label paint (never </code>null</code>).
 391:      * 
 392:      * @see #setLabelPaint(Paint)
 393:      */
 394:     public Paint getLabelPaint() {
 395:         return this.labelPaint;
 396:     }
 397: 
 398:     /**
 399:      * Sets the label paint and sends a {@link MarkerChangeEvent} to all
 400:      * registered listeners.
 401:      *
 402:      * @param paint  the paint (<code>null</code> not permitted).
 403:      * 
 404:      * @see #getLabelPaint()
 405:      */
 406:     public void setLabelPaint(Paint paint) {
 407:         if (paint == null) {
 408:             throw new IllegalArgumentException("Null 'paint' argument.");
 409:         }
 410:         this.labelPaint = paint;
 411:         notifyListeners(new MarkerChangeEvent(this));
 412:     }
 413: 
 414:     /**
 415:      * Returns the label anchor.  This defines the position of the label 
 416:      * anchor, relative to the bounds of the marker.
 417:      *
 418:      * @return The label anchor (never <code>null</code>).
 419:      * 
 420:      * @see #setLabelAnchor(RectangleAnchor)
 421:      */
 422:     public RectangleAnchor getLabelAnchor() {
 423:         return this.labelAnchor;
 424:     }
 425: 
 426:     /**
 427:      * Sets the label anchor and sends a {@link MarkerChangeEvent} to all 
 428:      * registered listeners.  The anchor defines the position of the label 
 429:      * anchor, relative to the bounds of the marker.
 430:      *
 431:      * @param anchor  the anchor (<code>null</code> not permitted).
 432:      * 
 433:      * @see #getLabelAnchor()
 434:      */
 435:     public void setLabelAnchor(RectangleAnchor anchor) {
 436:         if (anchor == null) {
 437:             throw new IllegalArgumentException("Null 'anchor' argument.");
 438:         }
 439:         this.labelAnchor = anchor;
 440:         notifyListeners(new MarkerChangeEvent(this));
 441:     }
 442: 
 443:     /**
 444:      * Returns the label offset.
 445:      * 
 446:      * @return The label offset (never <code>null</code>).
 447:      * 
 448:      * @see #setLabelOffset(RectangleInsets)
 449:      */
 450:     public RectangleInsets getLabelOffset() {
 451:         return this.labelOffset;
 452:     }
 453:     
 454:     /**
 455:      * Sets the label offset and sends a {@link MarkerChangeEvent} to all
 456:      * registered listeners.
 457:      * 
 458:      * @param offset  the label offset (<code>null</code> not permitted).
 459:      * 
 460:      * @see #getLabelOffset()
 461:      */
 462:     public void setLabelOffset(RectangleInsets offset) {
 463:         if (offset == null) {
 464:             throw new IllegalArgumentException("Null 'offset' argument.");
 465:         }
 466:         this.labelOffset = offset;
 467:         notifyListeners(new MarkerChangeEvent(this));
 468:     }
 469:     
 470:     /**
 471:      * Returns the label offset type.
 472:      * 
 473:      * @return The type (never <code>null</code>).
 474:      * 
 475:      * @see #setLabelOffsetType(LengthAdjustmentType)
 476:      */
 477:     public LengthAdjustmentType getLabelOffsetType() {
 478:         return this.labelOffsetType;   
 479:     }
 480:     
 481:     /**
 482:      * Sets the label offset type and sends a {@link MarkerChangeEvent} to all
 483:      * registered listeners.
 484:      * 
 485:      * @param adj  the type (<code>null</code> not permitted).
 486:      * 
 487:      * @see #getLabelOffsetType()
 488:      */
 489:     public void setLabelOffsetType(LengthAdjustmentType adj) {
 490:         if (adj == null) {
 491:             throw new IllegalArgumentException("Null 'adj' argument.");
 492:         }
 493:         this.labelOffsetType = adj;    
 494:         notifyListeners(new MarkerChangeEvent(this));
 495:     }
 496:         
 497:     /**
 498:      * Returns the label text anchor.
 499:      * 
 500:      * @return The label text anchor (never <code>null</code>).
 501:      * 
 502:      * @see #setLabelTextAnchor(TextAnchor)
 503:      */
 504:     public TextAnchor getLabelTextAnchor() {
 505:         return this.labelTextAnchor;
 506:     }
 507:     
 508:     /**
 509:      * Sets the label text anchor and sends a {@link MarkerChangeEvent} to 
 510:      * all registered listeners.
 511:      * 
 512:      * @param anchor  the label text anchor (<code>null</code> not permitted).
 513:      * 
 514:      * @see #getLabelTextAnchor()
 515:      */
 516:     public void setLabelTextAnchor(TextAnchor anchor) {
 517:         if (anchor == null) { 
 518:             throw new IllegalArgumentException("Null 'anchor' argument.");
 519:         }
 520:         this.labelTextAnchor = anchor;
 521:         notifyListeners(new MarkerChangeEvent(this));
 522:     }
 523:     
 524:     /**
 525:      * Registers an object for notification of changes to the marker.
 526:      *
 527:      * @param listener  the object to be registered.
 528:      * 
 529:      * @since 1.0.3
 530:      */
 531:     public void addChangeListener(MarkerChangeListener listener) {
 532:         this.listenerList.add(MarkerChangeListener.class, listener);
 533:     }
 534: 
 535:     /**
 536:      * Unregisters an object for notification of changes to the marker.
 537:      *
 538:      * @param listener  the object to be unregistered.
 539:      * 
 540:      * @since 1.0.3
 541:      */
 542:     public void removeChangeListener(MarkerChangeListener listener) {
 543:         this.listenerList.remove(MarkerChangeListener.class, listener);
 544:     }
 545: 
 546:     /**
 547:      * Notifies all registered listeners that the marker has been modified.
 548:      *
 549:      * @param event  information about the change event.
 550:      * 
 551:      * @since 1.0.3
 552:      */
 553:     public void notifyListeners(MarkerChangeEvent event) {
 554: 
 555:         Object[] listeners = this.listenerList.getListenerList();
 556:         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 557:             if (listeners[i] == MarkerChangeListener.class) {
 558:                 ((MarkerChangeListener) listeners[i + 1]).markerChanged(event);
 559:             }
 560:         }
 561: 
 562:     }
 563: 
 564:     /**
 565:      * Returns an array containing all the listeners of the specified type.
 566:      * 
 567:      * @param listenerType  the listener type.
 568:      * 
 569:      * @return The array of listeners.
 570:      * 
 571:      * @since 1.0.3
 572:      */
 573:     public EventListener[] getListeners(Class listenerType) {
 574:         return this.listenerList.getListeners(listenerType);    
 575:     }
 576:     
 577:     /**
 578:      * Tests the marker for equality with an arbitrary object.
 579:      * 
 580:      * @param obj  the object (<code>null</code> permitted).
 581:      * 
 582:      * @return A boolean.
 583:      */
 584:     public boolean equals(Object obj) {
 585:         if (obj == this) {
 586:             return true;
 587:         }
 588:         if (!(obj instanceof Marker)) {
 589:             return false;
 590:         }
 591:         Marker that = (Marker) obj;
 592:         if (!PaintUtilities.equal(this.paint, that.paint)) {
 593:             return false;   
 594:         }
 595:         if (!ObjectUtilities.equal(this.stroke, that.stroke)) {
 596:             return false;
 597:         }
 598:         if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) {
 599:             return false;   
 600:         }
 601:         if (!ObjectUtilities.equal(this.outlineStroke, that.outlineStroke)) {
 602:             return false;
 603:         }
 604:         if (this.alpha != that.alpha) {
 605:             return false;
 606:         }
 607:         if (!ObjectUtilities.equal(this.label, that.label)) {
 608:             return false;
 609:         }
 610:         if (!ObjectUtilities.equal(this.labelFont, that.labelFont)) {
 611:             return false;
 612:         }
 613:         if (!PaintUtilities.equal(this.labelPaint, that.labelPaint)) {
 614:             return false;
 615:         }
 616:         if (this.labelAnchor != that.labelAnchor) {
 617:             return false;
 618:         }
 619:         if (this.labelTextAnchor != that.labelTextAnchor) {
 620:             return false;   
 621:         }
 622:         if (!ObjectUtilities.equal(this.labelOffset, that.labelOffset)) {
 623:             return false;
 624:         }
 625:         if (!this.labelOffsetType.equals(that.labelOffsetType)) {
 626:             return false;
 627:         }
 628:         return true;
 629:     }
 630:     
 631:     /**
 632:      * Creates a clone of the marker.
 633:      * 
 634:      * @return A clone.
 635:      * 
 636:      * @throws CloneNotSupportedException never.
 637:      */
 638:     public Object clone() throws CloneNotSupportedException {
 639:         return super.clone();
 640:     }
 641:     
 642:     /**
 643:      * Provides serialization support.
 644:      *
 645:      * @param stream  the output stream.
 646:      *
 647:      * @throws IOException  if there is an I/O error.
 648:      */
 649:     private void writeObject(ObjectOutputStream stream) throws IOException {
 650:         stream.defaultWriteObject();
 651:         SerialUtilities.writePaint(this.paint, stream);
 652:         SerialUtilities.writeStroke(this.stroke, stream);
 653:         SerialUtilities.writePaint(this.outlinePaint, stream);
 654:         SerialUtilities.writeStroke(this.outlineStroke, stream);
 655:         SerialUtilities.writePaint(this.labelPaint, stream);
 656:     }
 657: 
 658:     /**
 659:      * Provides serialization support.
 660:      *
 661:      * @param stream  the input stream.
 662:      *
 663:      * @throws IOException  if there is an I/O error.
 664:      * @throws ClassNotFoundException  if there is a classpath problem.
 665:      */
 666:     private void readObject(ObjectInputStream stream) 
 667:         throws IOException, ClassNotFoundException {
 668:         stream.defaultReadObject();
 669:         this.paint = SerialUtilities.readPaint(stream);
 670:         this.stroke = SerialUtilities.readStroke(stream);
 671:         this.outlinePaint = SerialUtilities.readPaint(stream);
 672:         this.outlineStroke = SerialUtilities.readStroke(stream);
 673:         this.labelPaint = SerialUtilities.readPaint(stream);
 674:     }
 675: 
 676: }