001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2014, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * -------------- 028 * Crosshair.java 029 * -------------- 030 * (C) Copyright 2009-2014, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * Changes: 036 * -------- 037 * 13-Feb-2009 : Version 1 (DG); 038 * 02-Jul-2013 : Use ParamChecks (DG); 039 * 040 */ 041 042package org.jfree.chart.plot; 043 044import java.awt.BasicStroke; 045import java.awt.Color; 046import java.awt.Font; 047import java.awt.Paint; 048import java.awt.Stroke; 049import java.beans.PropertyChangeListener; 050import java.beans.PropertyChangeSupport; 051import java.io.IOException; 052import java.io.ObjectInputStream; 053import java.io.ObjectOutputStream; 054import java.io.Serializable; 055import org.jfree.chart.HashUtilities; 056import org.jfree.chart.labels.CrosshairLabelGenerator; 057import org.jfree.chart.labels.StandardCrosshairLabelGenerator; 058import org.jfree.chart.util.ParamChecks; 059import org.jfree.io.SerialUtilities; 060import org.jfree.ui.RectangleAnchor; 061import org.jfree.util.PaintUtilities; 062import org.jfree.util.PublicCloneable; 063 064/** 065 * A crosshair for display on a plot. 066 * 067 * @since 1.0.13 068 */ 069public class Crosshair implements Cloneable, PublicCloneable, Serializable { 070 071 /** Flag controlling visibility. */ 072 private boolean visible; 073 074 /** The crosshair value. */ 075 private double value; 076 077 /** The paint for the crosshair line. */ 078 private transient Paint paint; 079 080 /** The stroke for the crosshair line. */ 081 private transient Stroke stroke; 082 083 /** 084 * A flag that controls whether or not the crosshair has a label 085 * visible. 086 */ 087 private boolean labelVisible; 088 089 /** 090 * The label anchor. 091 */ 092 private RectangleAnchor labelAnchor; 093 094 /** A label generator. */ 095 private CrosshairLabelGenerator labelGenerator; 096 097 /** 098 * The x-offset in Java2D units. 099 */ 100 private double labelXOffset; 101 102 /** 103 * The y-offset in Java2D units. 104 */ 105 private double labelYOffset; 106 107 /** 108 * The label font. 109 */ 110 private Font labelFont; 111 112 /** 113 * The label paint. 114 */ 115 private transient Paint labelPaint; 116 117 /** 118 * The label background paint. 119 */ 120 private transient Paint labelBackgroundPaint; 121 122 /** A flag that controls the visibility of the label outline. */ 123 private boolean labelOutlineVisible; 124 125 /** The label outline stroke. */ 126 private transient Stroke labelOutlineStroke; 127 128 /** The label outline paint. */ 129 private transient Paint labelOutlinePaint; 130 131 /** Property change support. */ 132 private transient PropertyChangeSupport pcs; 133 134 /** 135 * Creates a new crosshair with value 0.0. 136 */ 137 public Crosshair() { 138 this(0.0); 139 } 140 141 /** 142 * Creates a new crosshair with the specified value. 143 * 144 * @param value the value. 145 */ 146 public Crosshair(double value) { 147 this(value, Color.black, new BasicStroke(1.0f)); 148 } 149 150 /** 151 * Creates a new crosshair value with the specified value and line style. 152 * 153 * @param value the value. 154 * @param paint the line paint (<code>null</code> not permitted). 155 * @param stroke the line stroke (<code>null</code> not permitted). 156 */ 157 public Crosshair(double value, Paint paint, Stroke stroke) { 158 ParamChecks.nullNotPermitted(paint, "paint"); 159 ParamChecks.nullNotPermitted(stroke, "stroke"); 160 this.visible = true; 161 this.value = value; 162 this.paint = paint; 163 this.stroke = stroke; 164 this.labelVisible = false; 165 this.labelGenerator = new StandardCrosshairLabelGenerator(); 166 this.labelAnchor = RectangleAnchor.BOTTOM_LEFT; 167 this.labelXOffset = 3.0; 168 this.labelYOffset = 3.0; 169 this.labelFont = new Font("Tahoma", Font.PLAIN, 12); 170 this.labelPaint = Color.black; 171 this.labelBackgroundPaint = new Color(0, 0, 255, 63); 172 this.labelOutlineVisible = true; 173 this.labelOutlinePaint = Color.black; 174 this.labelOutlineStroke = new BasicStroke(0.5f); 175 this.pcs = new PropertyChangeSupport(this); 176 } 177 178 /** 179 * Returns the flag that indicates whether or not the crosshair is 180 * currently visible. 181 * 182 * @return A boolean. 183 * 184 * @see #setVisible(boolean) 185 */ 186 public boolean isVisible() { 187 return this.visible; 188 } 189 190 /** 191 * Sets the flag that controls the visibility of the crosshair and sends 192 * a proerty change event (with the name 'visible') to all registered 193 * listeners. 194 * 195 * @param visible the new flag value. 196 * 197 * @see #isVisible() 198 */ 199 public void setVisible(boolean visible) { 200 boolean old = this.visible; 201 this.visible = visible; 202 this.pcs.firePropertyChange("visible", old, visible); 203 } 204 205 /** 206 * Returns the crosshair value. 207 * 208 * @return The crosshair value. 209 * 210 * @see #setValue(double) 211 */ 212 public double getValue() { 213 return this.value; 214 } 215 216 /** 217 * Sets the crosshair value and sends a property change event with the name 218 * 'value' to all registered listeners. 219 * 220 * @param value the value. 221 * 222 * @see #getValue() 223 */ 224 public void setValue(double value) { 225 Double oldValue = new Double(this.value); 226 this.value = value; 227 this.pcs.firePropertyChange("value", oldValue, new Double(value)); 228 } 229 230 /** 231 * Returns the paint for the crosshair line. 232 * 233 * @return The paint (never <code>null</code>). 234 * 235 * @see #setPaint(java.awt.Paint) 236 */ 237 public Paint getPaint() { 238 return this.paint; 239 } 240 241 /** 242 * Sets the paint for the crosshair line and sends a property change event 243 * with the name "paint" to all registered listeners. 244 * 245 * @param paint the paint (<code>null</code> not permitted). 246 * 247 * @see #getPaint() 248 */ 249 public void setPaint(Paint paint) { 250 Paint old = this.paint; 251 this.paint = paint; 252 this.pcs.firePropertyChange("paint", old, paint); 253 } 254 255 /** 256 * Returns the stroke for the crosshair line. 257 * 258 * @return The stroke (never <code>null</code>). 259 * 260 * @see #setStroke(java.awt.Stroke) 261 */ 262 public Stroke getStroke() { 263 return this.stroke; 264 } 265 266 /** 267 * Sets the stroke for the crosshair line and sends a property change event 268 * with the name "stroke" to all registered listeners. 269 * 270 * @param stroke the stroke (<code>null</code> not permitted). 271 * 272 * @see #getStroke() 273 */ 274 public void setStroke(Stroke stroke) { 275 Stroke old = this.stroke; 276 this.stroke = stroke; 277 this.pcs.firePropertyChange("stroke", old, stroke); 278 } 279 280 /** 281 * Returns the flag that controls whether or not a label is drawn for 282 * this crosshair. 283 * 284 * @return A boolean. 285 * 286 * @see #setLabelVisible(boolean) 287 */ 288 public boolean isLabelVisible() { 289 return this.labelVisible; 290 } 291 292 /** 293 * Sets the flag that controls whether or not a label is drawn for the 294 * crosshair and sends a property change event (with the name 295 * 'labelVisible') to all registered listeners. 296 * 297 * @param visible the new flag value. 298 * 299 * @see #isLabelVisible() 300 */ 301 public void setLabelVisible(boolean visible) { 302 boolean old = this.labelVisible; 303 this.labelVisible = visible; 304 this.pcs.firePropertyChange("labelVisible", old, visible); 305 } 306 307 /** 308 * Returns the crosshair label generator. 309 * 310 * @return The label crosshair generator (never <code>null</code>). 311 * 312 * @see #setLabelGenerator(org.jfree.chart.labels.CrosshairLabelGenerator) 313 */ 314 public CrosshairLabelGenerator getLabelGenerator() { 315 return this.labelGenerator; 316 } 317 318 /** 319 * Sets the crosshair label generator and sends a property change event 320 * (with the name 'labelGenerator') to all registered listeners. 321 * 322 * @param generator the new generator (<code>null</code> not permitted). 323 * 324 * @see #getLabelGenerator() 325 */ 326 public void setLabelGenerator(CrosshairLabelGenerator generator) { 327 ParamChecks.nullNotPermitted(generator, "generator"); 328 CrosshairLabelGenerator old = this.labelGenerator; 329 this.labelGenerator = generator; 330 this.pcs.firePropertyChange("labelGenerator", old, generator); 331 } 332 333 /** 334 * Returns the label anchor point. 335 * 336 * @return the label anchor point (never <code>null</code>. 337 * 338 * @see #setLabelAnchor(org.jfree.ui.RectangleAnchor) 339 */ 340 public RectangleAnchor getLabelAnchor() { 341 return this.labelAnchor; 342 } 343 344 /** 345 * Sets the label anchor point and sends a property change event (with the 346 * name 'labelAnchor') to all registered listeners. 347 * 348 * @param anchor the anchor (<code>null</code> not permitted). 349 * 350 * @see #getLabelAnchor() 351 */ 352 public void setLabelAnchor(RectangleAnchor anchor) { 353 RectangleAnchor old = this.labelAnchor; 354 this.labelAnchor = anchor; 355 this.pcs.firePropertyChange("labelAnchor", old, anchor); 356 } 357 358 /** 359 * Returns the x-offset for the label (in Java2D units). 360 * 361 * @return The x-offset. 362 * 363 * @see #setLabelXOffset(double) 364 */ 365 public double getLabelXOffset() { 366 return this.labelXOffset; 367 } 368 369 /** 370 * Sets the x-offset and sends a property change event (with the name 371 * 'labelXOffset') to all registered listeners. 372 * 373 * @param offset the new offset. 374 * 375 * @see #getLabelXOffset() 376 */ 377 public void setLabelXOffset(double offset) { 378 Double old = new Double(this.labelXOffset); 379 this.labelXOffset = offset; 380 this.pcs.firePropertyChange("labelXOffset", old, new Double(offset)); 381 } 382 383 /** 384 * Returns the y-offset for the label (in Java2D units). 385 * 386 * @return The y-offset. 387 * 388 * @see #setLabelYOffset(double) 389 */ 390 public double getLabelYOffset() { 391 return this.labelYOffset; 392 } 393 394 /** 395 * Sets the y-offset and sends a property change event (with the name 396 * 'labelYOffset') to all registered listeners. 397 * 398 * @param offset the new offset. 399 * 400 * @see #getLabelYOffset() 401 */ 402 public void setLabelYOffset(double offset) { 403 Double old = new Double(this.labelYOffset); 404 this.labelYOffset = offset; 405 this.pcs.firePropertyChange("labelYOffset", old, new Double(offset)); 406 } 407 408 /** 409 * Returns the label font. 410 * 411 * @return The label font (never <code>null</code>). 412 * 413 * @see #setLabelFont(java.awt.Font) 414 */ 415 public Font getLabelFont() { 416 return this.labelFont; 417 } 418 419 /** 420 * Sets the label font and sends a property change event (with the name 421 * 'labelFont') to all registered listeners. 422 * 423 * @param font the font (<code>null</code> not permitted). 424 * 425 * @see #getLabelFont() 426 */ 427 public void setLabelFont(Font font) { 428 ParamChecks.nullNotPermitted(font, "font"); 429 Font old = this.labelFont; 430 this.labelFont = font; 431 this.pcs.firePropertyChange("labelFont", old, font); 432 } 433 434 /** 435 * Returns the label paint. 436 * 437 * @return The label paint (never <code>null</code>). 438 * 439 * @see #setLabelPaint 440 */ 441 public Paint getLabelPaint() { 442 return this.labelPaint; 443 } 444 445 /** 446 * Sets the label paint and sends a property change event (with the name 447 * 'labelPaint') to all registered listeners. 448 * 449 * @param paint the paint (<code>null</code> not permitted). 450 * 451 * @see #getLabelPaint() 452 */ 453 public void setLabelPaint(Paint paint) { 454 ParamChecks.nullNotPermitted(paint, "paint"); 455 Paint old = this.labelPaint; 456 this.labelPaint = paint; 457 this.pcs.firePropertyChange("labelPaint", old, paint); 458 } 459 460 /** 461 * Returns the label background paint. 462 * 463 * @return The label background paint (possibly <code>null</code>). 464 * 465 * @see #setLabelBackgroundPaint(java.awt.Paint) 466 */ 467 public Paint getLabelBackgroundPaint() { 468 return this.labelBackgroundPaint; 469 } 470 471 /** 472 * Sets the label background paint and sends a property change event with 473 * the name 'labelBackgroundPaint') to all registered listeners. 474 * 475 * @param paint the paint (<code>null</code> permitted). 476 * 477 * @see #getLabelBackgroundPaint() 478 */ 479 public void setLabelBackgroundPaint(Paint paint) { 480 Paint old = this.labelBackgroundPaint; 481 this.labelBackgroundPaint = paint; 482 this.pcs.firePropertyChange("labelBackgroundPaint", old, paint); 483 } 484 485 /** 486 * Returns the flag that controls the visibility of the label outline. 487 * 488 * @return A boolean. 489 * 490 * @see #setLabelOutlineVisible(boolean) 491 */ 492 public boolean isLabelOutlineVisible() { 493 return this.labelOutlineVisible; 494 } 495 496 /** 497 * Sets the flag that controls the visibility of the label outlines and 498 * sends a property change event (with the name "labelOutlineVisible") to 499 * all registered listeners. 500 * 501 * @param visible the new flag value. 502 * 503 * @see #isLabelOutlineVisible() 504 */ 505 public void setLabelOutlineVisible(boolean visible) { 506 boolean old = this.labelOutlineVisible; 507 this.labelOutlineVisible = visible; 508 this.pcs.firePropertyChange("labelOutlineVisible", old, visible); 509 } 510 511 /** 512 * Returns the label outline paint. 513 * 514 * @return The label outline paint (never <code>null</code>). 515 * 516 * @see #setLabelOutlinePaint(java.awt.Paint) 517 */ 518 public Paint getLabelOutlinePaint() { 519 return this.labelOutlinePaint; 520 } 521 522 /** 523 * Sets the label outline paint and sends a property change event (with the 524 * name "labelOutlinePaint") to all registered listeners. 525 * 526 * @param paint the paint (<code>null</code> not permitted). 527 * 528 * @see #getLabelOutlinePaint() 529 */ 530 public void setLabelOutlinePaint(Paint paint) { 531 ParamChecks.nullNotPermitted(paint, "paint"); 532 Paint old = this.labelOutlinePaint; 533 this.labelOutlinePaint = paint; 534 this.pcs.firePropertyChange("labelOutlinePaint", old, paint); 535 } 536 537 /** 538 * Returns the label outline stroke. 539 * 540 * @return The label outline stroke (never <code>null</code>). 541 * 542 * @see #setLabelOutlineStroke(java.awt.Stroke) 543 */ 544 public Stroke getLabelOutlineStroke() { 545 return this.labelOutlineStroke; 546 } 547 548 /** 549 * Sets the label outline stroke and sends a property change event (with 550 * the name 'labelOutlineStroke') to all registered listeners. 551 * 552 * @param stroke the stroke (<code>null</code> not permitted). 553 * 554 * @see #getLabelOutlineStroke() 555 */ 556 public void setLabelOutlineStroke(Stroke stroke) { 557 ParamChecks.nullNotPermitted(stroke, "stroke"); 558 Stroke old = this.labelOutlineStroke; 559 this.labelOutlineStroke = stroke; 560 this.pcs.firePropertyChange("labelOutlineStroke", old, stroke); 561 } 562 563 /** 564 * Tests this crosshair for equality with an arbitrary object. 565 * 566 * @param obj the object (<code>null</code> permitted). 567 * 568 * @return A boolean. 569 */ 570 @Override 571 public boolean equals(Object obj) { 572 if (obj == this) { 573 return true; 574 } 575 if (!(obj instanceof Crosshair)) { 576 return false; 577 } 578 Crosshair that = (Crosshair) obj; 579 if (this.visible != that.visible) { 580 return false; 581 } 582 if (this.value != that.value) { 583 return false; 584 } 585 if (!PaintUtilities.equal(this.paint, that.paint)) { 586 return false; 587 } 588 if (!this.stroke.equals(that.stroke)) { 589 return false; 590 } 591 if (this.labelVisible != that.labelVisible) { 592 return false; 593 } 594 if (!this.labelGenerator.equals(that.labelGenerator)) { 595 return false; 596 } 597 if (!this.labelAnchor.equals(that.labelAnchor)) { 598 return false; 599 } 600 if (this.labelXOffset != that.labelXOffset) { 601 return false; 602 } 603 if (this.labelYOffset != that.labelYOffset) { 604 return false; 605 } 606 if (!this.labelFont.equals(that.labelFont)) { 607 return false; 608 } 609 if (!PaintUtilities.equal(this.labelPaint, that.labelPaint)) { 610 return false; 611 } 612 if (!PaintUtilities.equal(this.labelBackgroundPaint, 613 that.labelBackgroundPaint)) { 614 return false; 615 } 616 if (this.labelOutlineVisible != that.labelOutlineVisible) { 617 return false; 618 } 619 if (!PaintUtilities.equal(this.labelOutlinePaint, 620 that.labelOutlinePaint)) { 621 return false; 622 } 623 if (!this.labelOutlineStroke.equals(that.labelOutlineStroke)) { 624 return false; 625 } 626 return true; // can't find any difference 627 } 628 629 /** 630 * Returns a hash code for this instance. 631 * 632 * @return A hash code. 633 */ 634 @Override 635 public int hashCode() { 636 int hash = 7; 637 hash = HashUtilities.hashCode(hash, this.visible); 638 hash = HashUtilities.hashCode(hash, this.value); 639 hash = HashUtilities.hashCode(hash, this.paint); 640 hash = HashUtilities.hashCode(hash, this.stroke); 641 hash = HashUtilities.hashCode(hash, this.labelVisible); 642 hash = HashUtilities.hashCode(hash, this.labelAnchor); 643 hash = HashUtilities.hashCode(hash, this.labelGenerator); 644 hash = HashUtilities.hashCode(hash, this.labelXOffset); 645 hash = HashUtilities.hashCode(hash, this.labelYOffset); 646 hash = HashUtilities.hashCode(hash, this.labelFont); 647 hash = HashUtilities.hashCode(hash, this.labelPaint); 648 hash = HashUtilities.hashCode(hash, this.labelBackgroundPaint); 649 hash = HashUtilities.hashCode(hash, this.labelOutlineVisible); 650 hash = HashUtilities.hashCode(hash, this.labelOutlineStroke); 651 hash = HashUtilities.hashCode(hash, this.labelOutlinePaint); 652 return hash; 653 } 654 655 /** 656 * Returns an independent copy of this instance. 657 * 658 * @return An independent copy of this instance. 659 * 660 * @throws java.lang.CloneNotSupportedException if there is a problem with 661 * cloning. 662 */ 663 @Override 664 public Object clone() throws CloneNotSupportedException { 665 // FIXME: clone generator 666 return super.clone(); 667 } 668 669 /** 670 * Adds a property change listener. 671 * 672 * @param l the listener. 673 * 674 * @see #removePropertyChangeListener(java.beans.PropertyChangeListener) 675 */ 676 public void addPropertyChangeListener(PropertyChangeListener l) { 677 this.pcs.addPropertyChangeListener(l); 678 } 679 680 /** 681 * Removes a property change listener. 682 * 683 * @param l the listener. 684 * 685 * @see #addPropertyChangeListener(java.beans.PropertyChangeListener) 686 */ 687 public void removePropertyChangeListener(PropertyChangeListener l) { 688 this.pcs.removePropertyChangeListener(l); 689 } 690 691 /** 692 * Provides serialization support. 693 * 694 * @param stream the output stream. 695 * 696 * @throws IOException if there is an I/O error. 697 */ 698 private void writeObject(ObjectOutputStream stream) throws IOException { 699 stream.defaultWriteObject(); 700 SerialUtilities.writePaint(this.paint, stream); 701 SerialUtilities.writeStroke(this.stroke, stream); 702 SerialUtilities.writePaint(this.labelPaint, stream); 703 SerialUtilities.writePaint(this.labelBackgroundPaint, stream); 704 SerialUtilities.writeStroke(this.labelOutlineStroke, stream); 705 SerialUtilities.writePaint(this.labelOutlinePaint, stream); 706 } 707 708 /** 709 * Provides serialization support. 710 * 711 * @param stream the input stream. 712 * 713 * @throws IOException if there is an I/O error. 714 * @throws ClassNotFoundException if there is a classpath problem. 715 */ 716 private void readObject(ObjectInputStream stream) 717 throws IOException, ClassNotFoundException { 718 stream.defaultReadObject(); 719 this.paint = SerialUtilities.readPaint(stream); 720 this.stroke = SerialUtilities.readStroke(stream); 721 this.labelPaint = SerialUtilities.readPaint(stream); 722 this.labelBackgroundPaint = SerialUtilities.readPaint(stream); 723 this.labelOutlineStroke = SerialUtilities.readStroke(stream); 724 this.labelOutlinePaint = SerialUtilities.readPaint(stream); 725 this.pcs = new PropertyChangeSupport(this); 726 } 727 728}