Frames | No Frames |
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: }