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