001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2006, 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 * Marker.java 029 * ----------- 030 * (C) Copyright 2002-2006, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): Nicolas Brodu; 034 * 035 * $Id: Marker.java,v 1.10.2.4 2006/07/03 15:55:15 mungady Exp $ 036 * 037 * Changes (since 2-Jul-2002) 038 * -------------------------- 039 * 02-Jul-2002 : Added extra constructor, standard header and Javadoc 040 * comments (DG); 041 * 20-Aug-2002 : Added the outline stroke attribute (DG); 042 * 02-Oct-2002 : Fixed errors reported by Checkstyle (DG); 043 * 16-Oct-2002 : Added new constructor (DG); 044 * 26-Mar-2003 : Implemented Serializable (DG); 045 * 21-May-2003 : Added labels (DG); 046 * 11-Sep-2003 : Implemented Cloneable (NB); 047 * 05-Nov-2003 : Added checks to ensure some attributes are never null (DG); 048 * 11-Feb-2003 : Moved to org.jfree.chart.plot package, plus significant API 049 * changes to support IntervalMarker in plots (DG); 050 * 14-Jun-2004 : Updated equals() method (DG); 051 * 21-Jan-2005 : Added settings to control direction of horizontal and 052 * vertical label offsets (DG); 053 * 01-Jun-2005 : Modified to use only one label offset type - this will be 054 * applied to the domain or range axis as appropriate (DG); 055 * 06-Jun-2005 : Fix equals() method to handle GradientPaint (DG); 056 * 19-Aug-2005 : Changed constructor from public --> protected (DG); 057 * 058 */ 059 060 package org.jfree.chart.plot; 061 062 import java.awt.BasicStroke; 063 import java.awt.Color; 064 import java.awt.Font; 065 import java.awt.Paint; 066 import java.awt.Stroke; 067 import java.io.IOException; 068 import java.io.ObjectInputStream; 069 import java.io.ObjectOutputStream; 070 import java.io.Serializable; 071 072 import org.jfree.io.SerialUtilities; 073 import org.jfree.ui.LengthAdjustmentType; 074 import org.jfree.ui.RectangleAnchor; 075 import org.jfree.ui.RectangleInsets; 076 import org.jfree.ui.TextAnchor; 077 import org.jfree.util.ObjectUtilities; 078 import org.jfree.util.PaintUtilities; 079 080 /** 081 * The base class for markers that can be added to plots to highlight a value 082 * or range of values. 083 * <br><br> 084 * Note that there is no listener mechanism for markers, so changing the 085 * attributes for a marker will not lead to any automatic chart repainting. 086 */ 087 public abstract class Marker implements Cloneable, Serializable { 088 089 /** For serialization. */ 090 private static final long serialVersionUID = -734389651405327166L; 091 092 /** The paint. */ 093 private transient Paint paint; 094 095 /** The stroke. */ 096 private transient Stroke stroke; 097 098 /** The outline paint. */ 099 private transient Paint outlinePaint; 100 101 /** The outline stroke. */ 102 private transient Stroke outlineStroke; 103 104 /** The alpha transparency. */ 105 private float alpha; 106 107 /** The label. */ 108 private String label = null; 109 110 /** The label font. */ 111 private Font labelFont; 112 113 /** The label paint. */ 114 private transient Paint labelPaint; 115 116 /** The label position. */ 117 private RectangleAnchor labelAnchor; 118 119 /** The text anchor for the label. */ 120 private TextAnchor labelTextAnchor; 121 122 /** The label offset from the marker rectangle. */ 123 private RectangleInsets labelOffset; 124 125 /** 126 * The offset type for the domain or range axis (never <code>null</code>). 127 */ 128 private LengthAdjustmentType labelOffsetType; 129 130 /** 131 * Creates a new marker with default attributes. 132 */ 133 protected Marker() { 134 this(Color.gray); 135 } 136 137 /** 138 * Constructs a new marker. 139 * 140 * @param paint the paint (<code>null</code> not permitted). 141 */ 142 protected Marker(Paint paint) { 143 this(paint, new BasicStroke(0.5f), Color.gray, new BasicStroke(0.5f), 144 0.80f); 145 } 146 147 /** 148 * Constructs a new marker. 149 * 150 * @param paint the paint (<code>null</code> not permitted). 151 * @param stroke the stroke (<code>null</code> not permitted). 152 * @param outlinePaint the outline paint (<code>null</code> permitted). 153 * @param outlineStroke the outline stroke (<code>null</code> permitted). 154 * @param alpha the alpha transparency (must be in the range 0.0f to 155 * 1.0f). 156 * 157 * @throws IllegalArgumentException if <code>paint</code> or 158 * <code>stroke</code> is <code>null</code>, or <code>alpha</code> is 159 * not in the specified range. 160 */ 161 protected Marker(Paint paint, Stroke stroke, 162 Paint outlinePaint, Stroke outlineStroke, 163 float alpha) { 164 165 if (paint == null) { 166 throw new IllegalArgumentException("Null 'paint' argument."); 167 } 168 if (stroke == null) { 169 throw new IllegalArgumentException("Null 'stroke' argument."); 170 } 171 if (alpha < 0.0f || alpha > 1.0f) 172 throw new IllegalArgumentException( 173 "The 'alpha' value must be in the range 0.0f to 1.0f"); 174 175 this.paint = paint; 176 this.stroke = stroke; 177 this.outlinePaint = outlinePaint; 178 this.outlineStroke = outlineStroke; 179 this.alpha = alpha; 180 181 this.labelFont = new Font("SansSerif", Font.PLAIN, 9); 182 this.labelPaint = Color.black; 183 this.labelAnchor = RectangleAnchor.TOP_LEFT; 184 this.labelOffset = new RectangleInsets(3.0, 3.0, 3.0, 3.0); 185 this.labelOffsetType = LengthAdjustmentType.CONTRACT; 186 this.labelTextAnchor = TextAnchor.CENTER; 187 188 } 189 190 /** 191 * Returns the paint. 192 * 193 * @return The paint (never <code>null</code>). 194 * 195 * @see #setPaint(Paint) 196 */ 197 public Paint getPaint() { 198 return this.paint; 199 } 200 201 /** 202 * Sets the paint. 203 * 204 * @param paint the paint (<code>null</code> not permitted). 205 * 206 * @see #getPaint() 207 */ 208 public void setPaint(Paint paint) { 209 if (paint == null) { 210 throw new IllegalArgumentException("Null 'paint' argument."); 211 } 212 this.paint = paint; 213 } 214 215 /** 216 * Returns the stroke. 217 * 218 * @return The stroke (never <code>null</code>). 219 * 220 * @see #setStroke(Stroke) 221 */ 222 public Stroke getStroke() { 223 return this.stroke; 224 } 225 226 /** 227 * Sets the stroke. 228 * 229 * @param stroke the stroke (<code>null</code> not permitted). 230 * 231 * @see #getStroke() 232 */ 233 public void setStroke(Stroke stroke) { 234 if (stroke == null) { 235 throw new IllegalArgumentException("Null 'stroke' argument."); 236 } 237 this.stroke = stroke; 238 } 239 240 /** 241 * Returns the outline paint. 242 * 243 * @return The outline paint (possibly <code>null</code>). 244 * 245 * @see #setOutlinePaint(Paint) 246 */ 247 public Paint getOutlinePaint() { 248 return this.outlinePaint; 249 } 250 251 /** 252 * Sets the outline paint. 253 * 254 * @param paint the paint (<code>null</code> permitted). 255 * 256 * @see #getOutlinePaint() 257 */ 258 public void setOutlinePaint(Paint paint) { 259 this.outlinePaint = paint; 260 } 261 262 /** 263 * Returns the outline stroke. 264 * 265 * @return The outline stroke (possibly <code>null</code>). 266 * 267 * @see #setOutlineStroke(Stroke) 268 */ 269 public Stroke getOutlineStroke() { 270 return this.outlineStroke; 271 } 272 273 /** 274 * Sets the outline stroke. 275 * 276 * @param stroke the stroke (<code>null</code> permitted). 277 * 278 * @see #getOutlineStroke() 279 */ 280 public void setOutlineStroke(Stroke stroke) { 281 this.outlineStroke = stroke; 282 } 283 284 /** 285 * Returns the alpha transparency. 286 * 287 * @return The alpha transparency. 288 * 289 * @see #setAlpha(float) 290 */ 291 public float getAlpha() { 292 return this.alpha; 293 } 294 295 /** 296 * Sets the alpha transparency that should be used when drawing the 297 * marker. This is a value in the range 0.0f (completely transparent) to 298 * 1.0f (completely opaque). 299 * 300 * @param alpha the alpha transparency (must be in the range 0.0f to 301 * 1.0f). 302 * 303 * @throws IllegalArgumentException if <code>alpha</code> is not in the 304 * specified range. 305 * 306 * @see #getAlpha() 307 */ 308 public void setAlpha(float alpha) { 309 if (alpha < 0.0f || alpha > 1.0f) 310 throw new IllegalArgumentException( 311 "The 'alpha' value must be in the range 0.0f to 1.0f"); 312 this.alpha = alpha; 313 } 314 315 /** 316 * Returns the label (if <code>null</code> no label is displayed). 317 * 318 * @return The label (possibly <code>null</code>). 319 * 320 * @see #setLabel(String) 321 */ 322 public String getLabel() { 323 return this.label; 324 } 325 326 /** 327 * Sets the label (if <code>null</code> no label is displayed). 328 * 329 * @param label the label (<code>null</code> permitted). 330 * 331 * @see #getLabel() 332 */ 333 public void setLabel(String label) { 334 this.label = label; 335 } 336 337 /** 338 * Returns the label font. 339 * 340 * @return The label font (never <code>null</code>). 341 * 342 * @see #setLabelFont(Font) 343 */ 344 public Font getLabelFont() { 345 return this.labelFont; 346 } 347 348 /** 349 * Sets the label font. 350 * 351 * @param font the font (<code>null</code> not permitted). 352 * 353 * @see #getLabelFont() 354 */ 355 public void setLabelFont(Font font) { 356 if (font == null) { 357 throw new IllegalArgumentException("Null 'font' argument."); 358 } 359 this.labelFont = font; 360 } 361 362 /** 363 * Returns the label paint. 364 * 365 * @return The label paint (never </code>null</code>). 366 * 367 * @see #setLabelPaint(Paint) 368 */ 369 public Paint getLabelPaint() { 370 return this.labelPaint; 371 } 372 373 /** 374 * Sets the label paint. 375 * 376 * @param paint the paint (<code>null</code> not permitted). 377 * 378 * @see #getLabelPaint() 379 */ 380 public void setLabelPaint(Paint paint) { 381 if (paint == null) { 382 throw new IllegalArgumentException("Null 'paint' argument."); 383 } 384 this.labelPaint = paint; 385 } 386 387 /** 388 * Returns the label anchor. This defines the position of the label 389 * anchor, relative to the bounds of the marker. 390 * 391 * @return The label anchor (never <code>null</code>). 392 * 393 * @see #setLabelAnchor(RectangleAnchor) 394 */ 395 public RectangleAnchor getLabelAnchor() { 396 return this.labelAnchor; 397 } 398 399 /** 400 * Sets the label anchor. This defines the position of the label 401 * anchor, relative to the bounds of the marker. 402 * 403 * @param anchor the anchor (<code>null</code> not permitted). 404 * 405 * @see #getLabelAnchor() 406 */ 407 public void setLabelAnchor(RectangleAnchor anchor) { 408 if (anchor == null) { 409 throw new IllegalArgumentException("Null 'anchor' argument."); 410 } 411 this.labelAnchor = anchor; 412 } 413 414 /** 415 * Returns the label offset. 416 * 417 * @return The label offset (never <code>null</code>). 418 * 419 * @see #setLabelOffset(RectangleInsets) 420 */ 421 public RectangleInsets getLabelOffset() { 422 return this.labelOffset; 423 } 424 425 /** 426 * Sets the label offset. 427 * 428 * @param offset the label offset (<code>null</code> not permitted). 429 * 430 * @see #getLabelOffset() 431 */ 432 public void setLabelOffset(RectangleInsets offset) { 433 if (offset == null) { 434 throw new IllegalArgumentException("Null 'offset' argument."); 435 } 436 this.labelOffset = offset; 437 } 438 439 /** 440 * Returns the label offset type. 441 * 442 * @return The type (never <code>null</code>). 443 * 444 * @see #setLabelOffsetType(LengthAdjustmentType) 445 */ 446 public LengthAdjustmentType getLabelOffsetType() { 447 return this.labelOffsetType; 448 } 449 450 /** 451 * Sets the label offset type. 452 * 453 * @param adj the type (<code>null</code> not permitted). 454 * 455 * @see #getLabelOffsetType() 456 */ 457 public void setLabelOffsetType(LengthAdjustmentType adj) { 458 if (adj == null) { 459 throw new IllegalArgumentException("Null 'adj' argument."); 460 } 461 this.labelOffsetType = adj; 462 } 463 464 /** 465 * Returns the label text anchor. 466 * 467 * @return The label text anchor (never <code>null</code>). 468 * 469 * @see #setLabelTextAnchor(TextAnchor) 470 */ 471 public TextAnchor getLabelTextAnchor() { 472 return this.labelTextAnchor; 473 } 474 475 /** 476 * Sets the label text anchor. 477 * 478 * @param anchor the label text anchor (<code>null</code> not permitted). 479 * 480 * @see #getLabelTextAnchor() 481 */ 482 public void setLabelTextAnchor(TextAnchor anchor) { 483 if (anchor == null) { 484 throw new IllegalArgumentException("Null 'anchor' argument."); 485 } 486 this.labelTextAnchor = anchor; 487 } 488 489 /** 490 * Tests the marker for equality with an arbitrary object. 491 * 492 * @param obj the object (<code>null</code> permitted). 493 * 494 * @return A boolean. 495 */ 496 public boolean equals(Object obj) { 497 if (obj == this) { 498 return true; 499 } 500 if (!(obj instanceof Marker)) { 501 return false; 502 } 503 Marker that = (Marker) obj; 504 if (!PaintUtilities.equal(this.paint, that.paint)) { 505 return false; 506 } 507 if (!ObjectUtilities.equal(this.stroke, that.stroke)) { 508 return false; 509 } 510 if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) { 511 return false; 512 } 513 if (!ObjectUtilities.equal(this.outlineStroke, that.outlineStroke)) { 514 return false; 515 } 516 if (this.alpha != that.alpha) { 517 return false; 518 } 519 if (!ObjectUtilities.equal(this.label, that.label)) { 520 return false; 521 } 522 if (!ObjectUtilities.equal(this.labelFont, that.labelFont)) { 523 return false; 524 } 525 if (!PaintUtilities.equal(this.labelPaint, that.labelPaint)) { 526 return false; 527 } 528 if (this.labelAnchor != that.labelAnchor) { 529 return false; 530 } 531 if (this.labelTextAnchor != that.labelTextAnchor) { 532 return false; 533 } 534 if (!ObjectUtilities.equal(this.labelOffset, that.labelOffset)) { 535 return false; 536 } 537 if (!this.labelOffsetType.equals(that.labelOffsetType)) { 538 return false; 539 } 540 return true; 541 } 542 543 /** 544 * Creates a clone of the marker. 545 * 546 * @return A clone. 547 * 548 * @throws CloneNotSupportedException never. 549 */ 550 public Object clone() throws CloneNotSupportedException { 551 return super.clone(); 552 } 553 554 /** 555 * Provides serialization support. 556 * 557 * @param stream the output stream. 558 * 559 * @throws IOException if there is an I/O error. 560 */ 561 private void writeObject(ObjectOutputStream stream) throws IOException { 562 stream.defaultWriteObject(); 563 SerialUtilities.writePaint(this.paint, stream); 564 SerialUtilities.writeStroke(this.stroke, stream); 565 SerialUtilities.writePaint(this.outlinePaint, stream); 566 SerialUtilities.writeStroke(this.outlineStroke, stream); 567 SerialUtilities.writePaint(this.labelPaint, stream); 568 } 569 570 /** 571 * Provides serialization support. 572 * 573 * @param stream the input stream. 574 * 575 * @throws IOException if there is an I/O error. 576 * @throws ClassNotFoundException if there is a classpath problem. 577 */ 578 private void readObject(ObjectInputStream stream) 579 throws IOException, ClassNotFoundException { 580 stream.defaultReadObject(); 581 this.paint = SerialUtilities.readPaint(stream); 582 this.stroke = SerialUtilities.readStroke(stream); 583 this.outlinePaint = SerialUtilities.readPaint(stream); 584 this.outlineStroke = SerialUtilities.readStroke(stream); 585 this.labelPaint = SerialUtilities.readPaint(stream); 586 } 587 588 }