001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2007, 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 * SymbolAxis.java 029 * --------------- 030 * (C) Copyright 2002-2007, by Object Refinery Limited and Contributors. 031 * 032 * Original Author: Anthony Boulestreau; 033 * Contributor(s): David Gilbert (for Object Refinery Limited); 034 * 035 * 036 * Changes (from 23-Jun-2001) 037 * -------------------------- 038 * 29-Mar-2002 : First version (AB); 039 * 19-Apr-2002 : Updated formatting and import statements (DG); 040 * 21-Jun-2002 : Make change to use the class TickUnit - remove valueToString() 041 * method and add SymbolicTickUnit (AB); 042 * 25-Jun-2002 : Removed redundant code (DG); 043 * 25-Jul-2002 : Changed order of parameters in ValueAxis constructor (DG); 044 * 05-Sep-2002 : Updated constructor to reflect changes in the Axis class (DG); 045 * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG); 046 * 14-Feb-2003 : Added back missing constructor code (DG); 047 * 26-Mar-2003 : Implemented Serializable (DG); 048 * 14-May-2003 : Renamed HorizontalSymbolicAxis --> SymbolicAxis and merged in 049 * VerticalSymbolicAxis (DG); 050 * 12-Aug-2003 : Fixed bug where refreshTicks() method has different signature 051 * to super class (DG); 052 * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG); 053 * 02-Nov-2003 : Added code to avoid overlapping labels (MR); 054 * 07-Nov-2003 : Modified to use new tick classes (DG); 055 * 18-Nov-2003 : Fixed bug where symbols are not being displayed on the 056 * axis (DG); 057 * 24-Nov-2003 : Added fix for gridlines on zooming (bug id 834643) (DG); 058 * 21-Jan-2004 : Update for renamed method in ValueAxis (DG); 059 * 11-Mar-2004 : Modified the way the background grid color is being drawn, see 060 * this thread: 061 * http://www.jfree.org/phpBB2/viewtopic.php?p=22973 (DG); 062 * 16-Mar-2004 : Added plotState to draw() method (DG); 063 * 07-Apr-2004 : Modified string bounds calculation (DG); 064 * 28-Mar-2005 : Renamed autoRangeIncludesZero() --> getAutoRangeIncludesZero() 065 * and autoRangeStickyZero() --> getAutoRangeStickyZero() (DG); 066 * 05-Jul-2005 : Fixed signature on refreshTicks() method - see bug report 067 * 1232264 (DG); 068 * 06-Jul-2005 : Renamed SymbolicAxis --> SymbolAxis, added equals() method, 069 * renamed getSymbolicValue() --> getSymbols(), renamed 070 * symbolicGridPaint --> gridBandPaint, fixed serialization of 071 * gridBandPaint, renamed symbolicGridLinesVisible --> 072 * gridBandsVisible, eliminated symbolicGridLineList (DG); 073 * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG); 074 * 075 */ 076 077 package org.jfree.chart.axis; 078 079 import java.awt.BasicStroke; 080 import java.awt.Color; 081 import java.awt.Font; 082 import java.awt.Graphics2D; 083 import java.awt.Paint; 084 import java.awt.Shape; 085 import java.awt.geom.Rectangle2D; 086 import java.io.IOException; 087 import java.io.ObjectInputStream; 088 import java.io.ObjectOutputStream; 089 import java.io.Serializable; 090 import java.text.NumberFormat; 091 import java.util.Arrays; 092 import java.util.Iterator; 093 import java.util.List; 094 095 import org.jfree.chart.event.AxisChangeEvent; 096 import org.jfree.chart.plot.Plot; 097 import org.jfree.chart.plot.PlotRenderingInfo; 098 import org.jfree.chart.plot.ValueAxisPlot; 099 import org.jfree.data.Range; 100 import org.jfree.io.SerialUtilities; 101 import org.jfree.text.TextUtilities; 102 import org.jfree.ui.RectangleEdge; 103 import org.jfree.ui.TextAnchor; 104 import org.jfree.util.PaintUtilities; 105 106 /** 107 * A standard linear value axis that replaces integer values with symbols. 108 */ 109 public class SymbolAxis extends NumberAxis implements Serializable { 110 111 /** For serialization. */ 112 private static final long serialVersionUID = 7216330468770619716L; 113 114 /** The default grid band paint. */ 115 public static final Paint DEFAULT_GRID_BAND_PAINT 116 = new Color(232, 234, 232, 128); 117 118 /** The list of symbols to display instead of the numeric values. */ 119 private List symbols; 120 121 /** The paint used to color the grid bands (if the bands are visible). */ 122 private transient Paint gridBandPaint; 123 124 /** Flag that indicates whether or not grid bands are visible. */ 125 private boolean gridBandsVisible; 126 127 /** 128 * Constructs a symbol axis, using default attribute values where 129 * necessary. 130 * 131 * @param label the axis label (null permitted). 132 * @param sv the list of symbols to display instead of the numeric 133 * values. 134 */ 135 public SymbolAxis(String label, String[] sv) { 136 super(label); 137 this.symbols = Arrays.asList(sv); 138 this.gridBandsVisible = true; 139 this.gridBandPaint = DEFAULT_GRID_BAND_PAINT; 140 141 setAutoTickUnitSelection(false, false); 142 setAutoRangeStickyZero(false); 143 144 } 145 146 /** 147 * Returns an array of the symbols for the axis. 148 * 149 * @return The symbols. 150 */ 151 public String[] getSymbols() { 152 String[] result = new String[this.symbols.size()]; 153 result = (String[]) this.symbols.toArray(result); 154 return result; 155 } 156 157 /** 158 * Returns the paint used to color the grid bands. 159 * 160 * @return The grid band paint (never <code>null</code>). 161 * 162 * @see #isGridBandsVisible() 163 */ 164 public Paint getGridBandPaint() { 165 return this.gridBandPaint; 166 } 167 168 /** 169 * Sets the grid band paint and sends an {@link AxisChangeEvent} to 170 * all registered listeners. 171 * 172 * @param paint the paint (<code>null</code> not permitted). 173 */ 174 public void setGridBandPaint(Paint paint) { 175 if (paint == null) { 176 throw new IllegalArgumentException("Null 'paint' argument."); 177 } 178 this.gridBandPaint = paint; 179 notifyListeners(new AxisChangeEvent(this)); 180 } 181 182 /** 183 * Returns <code>true</code> if the grid bands are showing, and 184 * <code>false</code> otherwise. 185 * 186 * @return <code>true</code> if the grid bands are showing, and 187 * <code>false</code> otherwise. 188 */ 189 public boolean isGridBandsVisible() { 190 return this.gridBandsVisible; 191 } 192 193 /** 194 * Sets the visibility of the grid bands and notifies registered 195 * listeners that the axis has been modified. 196 * 197 * @param flag the new setting. 198 */ 199 public void setGridBandsVisible(boolean flag) { 200 if (this.gridBandsVisible != flag) { 201 this.gridBandsVisible = flag; 202 notifyListeners(new AxisChangeEvent(this)); 203 } 204 } 205 206 /** 207 * This operation is not supported by this axis. 208 * 209 * @param g2 the graphics device. 210 * @param dataArea the area in which the plot and axes should be drawn. 211 * @param edge the edge along which the axis is drawn. 212 */ 213 protected void selectAutoTickUnit(Graphics2D g2, Rectangle2D dataArea, 214 RectangleEdge edge) { 215 throw new UnsupportedOperationException(); 216 } 217 218 /** 219 * Draws the axis on a Java 2D graphics device (such as the screen or a 220 * printer). 221 * 222 * @param g2 the graphics device (<code>null</code> not permitted). 223 * @param cursor the cursor location. 224 * @param plotArea the area within which the plot and axes should be drawn 225 * (<code>null</code> not permitted). 226 * @param dataArea the area within which the data should be drawn 227 * (<code>null</code> not permitted). 228 * @param edge the axis location (<code>null</code> not permitted). 229 * @param plotState collects information about the plot 230 * (<code>null</code> permitted). 231 * 232 * @return The axis state (never <code>null</code>). 233 */ 234 public AxisState draw(Graphics2D g2, 235 double cursor, 236 Rectangle2D plotArea, 237 Rectangle2D dataArea, 238 RectangleEdge edge, 239 PlotRenderingInfo plotState) { 240 241 AxisState info = new AxisState(cursor); 242 if (isVisible()) { 243 info = super.draw(g2, cursor, plotArea, dataArea, edge, plotState); 244 } 245 if (this.gridBandsVisible) { 246 drawGridBands(g2, plotArea, dataArea, edge, info.getTicks()); 247 } 248 return info; 249 250 } 251 252 /** 253 * Draws the grid bands. Alternate bands are colored using 254 * <CODE>gridBandPaint<CODE> (<CODE>DEFAULT_GRID_BAND_PAINT</CODE> by 255 * default). 256 * 257 * @param g2 the graphics device. 258 * @param plotArea the area within which the chart should be drawn. 259 * @param dataArea the area within which the plot should be drawn (a 260 * subset of the drawArea). 261 * @param edge the axis location. 262 * @param ticks the ticks. 263 */ 264 protected void drawGridBands(Graphics2D g2, 265 Rectangle2D plotArea, 266 Rectangle2D dataArea, 267 RectangleEdge edge, 268 List ticks) { 269 270 Shape savedClip = g2.getClip(); 271 g2.clip(dataArea); 272 if (RectangleEdge.isTopOrBottom(edge)) { 273 drawGridBandsHorizontal(g2, plotArea, dataArea, true, ticks); 274 } 275 else if (RectangleEdge.isLeftOrRight(edge)) { 276 drawGridBandsVertical(g2, plotArea, dataArea, true, ticks); 277 } 278 g2.setClip(savedClip); 279 280 } 281 282 /** 283 * Draws the grid bands for the axis when it is at the top or bottom of 284 * the plot. 285 * 286 * @param g2 the graphics device. 287 * @param plotArea the area within which the chart should be drawn. 288 * @param dataArea the area within which the plot should be drawn 289 * (a subset of the drawArea). 290 * @param firstGridBandIsDark True: the first grid band takes the 291 * color of <CODE>gridBandPaint<CODE>. 292 * False: the second grid band takes the 293 * color of <CODE>gridBandPaint<CODE>. 294 * @param ticks the ticks. 295 */ 296 protected void drawGridBandsHorizontal(Graphics2D g2, 297 Rectangle2D plotArea, 298 Rectangle2D dataArea, 299 boolean firstGridBandIsDark, 300 List ticks) { 301 302 boolean currentGridBandIsDark = firstGridBandIsDark; 303 double yy = dataArea.getY(); 304 double xx1, xx2; 305 306 //gets the outline stroke width of the plot 307 double outlineStrokeWidth; 308 if (getPlot().getOutlineStroke() != null) { 309 outlineStrokeWidth 310 = ((BasicStroke) getPlot().getOutlineStroke()).getLineWidth(); 311 } 312 else { 313 outlineStrokeWidth = 1d; 314 } 315 316 Iterator iterator = ticks.iterator(); 317 ValueTick tick; 318 Rectangle2D band; 319 while (iterator.hasNext()) { 320 tick = (ValueTick) iterator.next(); 321 xx1 = valueToJava2D( 322 tick.getValue() - 0.5d, dataArea, RectangleEdge.BOTTOM 323 ); 324 xx2 = valueToJava2D( 325 tick.getValue() + 0.5d, dataArea, RectangleEdge.BOTTOM 326 ); 327 if (currentGridBandIsDark) { 328 g2.setPaint(this.gridBandPaint); 329 } 330 else { 331 g2.setPaint(Color.white); 332 } 333 band = new Rectangle2D.Double(xx1, yy + outlineStrokeWidth, 334 xx2 - xx1, dataArea.getMaxY() - yy - outlineStrokeWidth); 335 g2.fill(band); 336 currentGridBandIsDark = !currentGridBandIsDark; 337 } 338 g2.setPaintMode(); 339 } 340 341 /** 342 * Draws the grid bands for the axis when it is at the top or bottom of 343 * the plot. 344 * 345 * @param g2 the graphics device. 346 * @param drawArea the area within which the chart should be drawn. 347 * @param plotArea the area within which the plot should be drawn (a 348 * subset of the drawArea). 349 * @param firstGridBandIsDark True: the first grid band takes the 350 * color of <CODE>gridBandPaint<CODE>. 351 * False: the second grid band takes the 352 * color of <CODE>gridBandPaint<CODE>. 353 * @param ticks a list of ticks. 354 */ 355 protected void drawGridBandsVertical(Graphics2D g2, 356 Rectangle2D drawArea, 357 Rectangle2D plotArea, 358 boolean firstGridBandIsDark, 359 List ticks) { 360 361 boolean currentGridBandIsDark = firstGridBandIsDark; 362 double xx = plotArea.getX(); 363 double yy1, yy2; 364 365 //gets the outline stroke width of the plot 366 double outlineStrokeWidth; 367 if (getPlot().getOutlineStroke() != null) { 368 outlineStrokeWidth 369 = ((BasicStroke) getPlot().getOutlineStroke()).getLineWidth(); 370 } 371 else { 372 outlineStrokeWidth = 1d; 373 } 374 375 Iterator iterator = ticks.iterator(); 376 ValueTick tick; 377 Rectangle2D band; 378 while (iterator.hasNext()) { 379 tick = (ValueTick) iterator.next(); 380 yy1 = valueToJava2D( 381 tick.getValue() + 0.5d, plotArea, RectangleEdge.LEFT 382 ); 383 yy2 = valueToJava2D( 384 tick.getValue() - 0.5d, plotArea, RectangleEdge.LEFT 385 ); 386 if (currentGridBandIsDark) { 387 g2.setPaint(this.gridBandPaint); 388 } 389 else { 390 g2.setPaint(Color.white); 391 } 392 band = new Rectangle2D.Double(xx + outlineStrokeWidth, 393 yy1, plotArea.getMaxX() - xx - outlineStrokeWidth, yy2 - yy1); 394 g2.fill(band); 395 currentGridBandIsDark = !currentGridBandIsDark; 396 } 397 g2.setPaintMode(); 398 } 399 400 /** 401 * Rescales the axis to ensure that all data is visible. 402 */ 403 protected void autoAdjustRange() { 404 405 Plot plot = getPlot(); 406 if (plot == null) { 407 return; // no plot, no data 408 } 409 410 if (plot instanceof ValueAxisPlot) { 411 412 // ensure that all the symbols are displayed 413 double upper = this.symbols.size() - 1; 414 double lower = 0; 415 double range = upper - lower; 416 417 // ensure the autorange is at least <minRange> in size... 418 double minRange = getAutoRangeMinimumSize(); 419 if (range < minRange) { 420 upper = (upper + lower + minRange) / 2; 421 lower = (upper + lower - minRange) / 2; 422 } 423 424 // this ensure that the grid bands will be displayed correctly. 425 double upperMargin = 0.5; 426 double lowerMargin = 0.5; 427 428 if (getAutoRangeIncludesZero()) { 429 if (getAutoRangeStickyZero()) { 430 if (upper <= 0.0) { 431 upper = 0.0; 432 } 433 else { 434 upper = upper + upperMargin; 435 } 436 if (lower >= 0.0) { 437 lower = 0.0; 438 } 439 else { 440 lower = lower - lowerMargin; 441 } 442 } 443 else { 444 upper = Math.max(0.0, upper + upperMargin); 445 lower = Math.min(0.0, lower - lowerMargin); 446 } 447 } 448 else { 449 if (getAutoRangeStickyZero()) { 450 if (upper <= 0.0) { 451 upper = Math.min(0.0, upper + upperMargin); 452 } 453 else { 454 upper = upper + upperMargin * range; 455 } 456 if (lower >= 0.0) { 457 lower = Math.max(0.0, lower - lowerMargin); 458 } 459 else { 460 lower = lower - lowerMargin; 461 } 462 } 463 else { 464 upper = upper + upperMargin; 465 lower = lower - lowerMargin; 466 } 467 } 468 469 setRange(new Range(lower, upper), false, false); 470 471 } 472 473 } 474 475 /** 476 * Calculates the positions of the tick labels for the axis, storing the 477 * results in the tick label list (ready for drawing). 478 * 479 * @param g2 the graphics device. 480 * @param state the axis state. 481 * @param dataArea the area in which the data should be drawn. 482 * @param edge the location of the axis. 483 * 484 * @return A list of ticks. 485 */ 486 public List refreshTicks(Graphics2D g2, 487 AxisState state, 488 Rectangle2D dataArea, 489 RectangleEdge edge) { 490 List ticks = null; 491 if (RectangleEdge.isTopOrBottom(edge)) { 492 ticks = refreshTicksHorizontal(g2, dataArea, edge); 493 } 494 else if (RectangleEdge.isLeftOrRight(edge)) { 495 ticks = refreshTicksVertical(g2, dataArea, edge); 496 } 497 return ticks; 498 } 499 500 /** 501 * Calculates the positions of the tick labels for the axis, storing the 502 * results in the tick label list (ready for drawing). 503 * 504 * @param g2 the graphics device. 505 * @param dataArea the area in which the data should be drawn. 506 * @param edge the location of the axis. 507 * 508 * @return The ticks. 509 */ 510 protected List refreshTicksHorizontal(Graphics2D g2, 511 Rectangle2D dataArea, 512 RectangleEdge edge) { 513 514 List ticks = new java.util.ArrayList(); 515 516 Font tickLabelFont = getTickLabelFont(); 517 g2.setFont(tickLabelFont); 518 519 double size = getTickUnit().getSize(); 520 int count = calculateVisibleTickCount(); 521 double lowestTickValue = calculateLowestVisibleTickValue(); 522 523 double previousDrawnTickLabelPos = 0.0; 524 double previousDrawnTickLabelLength = 0.0; 525 526 if (count <= ValueAxis.MAXIMUM_TICK_COUNT) { 527 for (int i = 0; i < count; i++) { 528 double currentTickValue = lowestTickValue + (i * size); 529 double xx = valueToJava2D(currentTickValue, dataArea, edge); 530 String tickLabel; 531 NumberFormat formatter = getNumberFormatOverride(); 532 if (formatter != null) { 533 tickLabel = formatter.format(currentTickValue); 534 } 535 else { 536 tickLabel = valueToString(currentTickValue); 537 } 538 539 // avoid to draw overlapping tick labels 540 Rectangle2D bounds = TextUtilities.getTextBounds( 541 tickLabel, g2, g2.getFontMetrics() 542 ); 543 double tickLabelLength = isVerticalTickLabels() 544 ? bounds.getHeight() : bounds.getWidth(); 545 boolean tickLabelsOverlapping = false; 546 if (i > 0) { 547 double avgTickLabelLength = (previousDrawnTickLabelLength 548 + tickLabelLength) / 2.0; 549 if (Math.abs(xx - previousDrawnTickLabelPos) 550 < avgTickLabelLength) { 551 tickLabelsOverlapping = true; 552 } 553 } 554 if (tickLabelsOverlapping) { 555 tickLabel = ""; // don't draw this tick label 556 } 557 else { 558 // remember these values for next comparison 559 previousDrawnTickLabelPos = xx; 560 previousDrawnTickLabelLength = tickLabelLength; 561 } 562 563 TextAnchor anchor = null; 564 TextAnchor rotationAnchor = null; 565 double angle = 0.0; 566 if (isVerticalTickLabels()) { 567 anchor = TextAnchor.CENTER_RIGHT; 568 rotationAnchor = TextAnchor.CENTER_RIGHT; 569 if (edge == RectangleEdge.TOP) { 570 angle = Math.PI / 2.0; 571 } 572 else { 573 angle = -Math.PI / 2.0; 574 } 575 } 576 else { 577 if (edge == RectangleEdge.TOP) { 578 anchor = TextAnchor.BOTTOM_CENTER; 579 rotationAnchor = TextAnchor.BOTTOM_CENTER; 580 } 581 else { 582 anchor = TextAnchor.TOP_CENTER; 583 rotationAnchor = TextAnchor.TOP_CENTER; 584 } 585 } 586 Tick tick = new NumberTick( 587 new Double(currentTickValue), tickLabel, anchor, 588 rotationAnchor, angle 589 ); 590 ticks.add(tick); 591 } 592 } 593 return ticks; 594 595 } 596 597 /** 598 * Calculates the positions of the tick labels for the axis, storing the 599 * results in the tick label list (ready for drawing). 600 * 601 * @param g2 the graphics device. 602 * @param dataArea the area in which the plot should be drawn. 603 * @param edge the location of the axis. 604 * 605 * @return The ticks. 606 */ 607 protected List refreshTicksVertical(Graphics2D g2, 608 Rectangle2D dataArea, 609 RectangleEdge edge) { 610 611 List ticks = new java.util.ArrayList(); 612 613 Font tickLabelFont = getTickLabelFont(); 614 g2.setFont(tickLabelFont); 615 616 double size = getTickUnit().getSize(); 617 int count = calculateVisibleTickCount(); 618 double lowestTickValue = calculateLowestVisibleTickValue(); 619 620 double previousDrawnTickLabelPos = 0.0; 621 double previousDrawnTickLabelLength = 0.0; 622 623 if (count <= ValueAxis.MAXIMUM_TICK_COUNT) { 624 for (int i = 0; i < count; i++) { 625 double currentTickValue = lowestTickValue + (i * size); 626 double yy = valueToJava2D(currentTickValue, dataArea, edge); 627 String tickLabel; 628 NumberFormat formatter = getNumberFormatOverride(); 629 if (formatter != null) { 630 tickLabel = formatter.format(currentTickValue); 631 } 632 else { 633 tickLabel = valueToString(currentTickValue); 634 } 635 636 // avoid to draw overlapping tick labels 637 Rectangle2D bounds = TextUtilities.getTextBounds( 638 tickLabel, g2, g2.getFontMetrics() 639 ); 640 double tickLabelLength = isVerticalTickLabels() 641 ? bounds.getWidth() : bounds.getHeight(); 642 boolean tickLabelsOverlapping = false; 643 if (i > 0) { 644 double avgTickLabelLength = 645 (previousDrawnTickLabelLength + tickLabelLength) / 2.0; 646 if (Math.abs(yy - previousDrawnTickLabelPos) 647 < avgTickLabelLength) { 648 tickLabelsOverlapping = true; 649 } 650 if (tickLabelsOverlapping) { 651 tickLabel = ""; // don't draw this tick label 652 } 653 else { 654 // remember these values for next comparison 655 previousDrawnTickLabelPos = yy; 656 previousDrawnTickLabelLength = tickLabelLength; 657 } 658 } 659 TextAnchor anchor = null; 660 TextAnchor rotationAnchor = null; 661 double angle = 0.0; 662 if (isVerticalTickLabels()) { 663 anchor = TextAnchor.BOTTOM_CENTER; 664 rotationAnchor = TextAnchor.BOTTOM_CENTER; 665 if (edge == RectangleEdge.LEFT) { 666 angle = -Math.PI / 2.0; 667 } 668 else { 669 angle = Math.PI / 2.0; 670 } 671 } 672 else { 673 if (edge == RectangleEdge.LEFT) { 674 anchor = TextAnchor.CENTER_RIGHT; 675 rotationAnchor = TextAnchor.CENTER_RIGHT; 676 } 677 else { 678 anchor = TextAnchor.CENTER_LEFT; 679 rotationAnchor = TextAnchor.CENTER_LEFT; 680 } 681 } 682 Tick tick = new NumberTick( 683 new Double(currentTickValue), tickLabel, anchor, 684 rotationAnchor, angle 685 ); 686 ticks.add(tick); 687 } 688 } 689 return ticks; 690 691 } 692 693 /** 694 * Converts a value to a string, using the list of symbols. 695 * 696 * @param value value to convert. 697 * 698 * @return The symbol. 699 */ 700 public String valueToString(double value) { 701 String strToReturn; 702 try { 703 strToReturn = (String) this.symbols.get((int) value); 704 } 705 catch (IndexOutOfBoundsException ex) { 706 strToReturn = ""; 707 } 708 return strToReturn; 709 } 710 711 /** 712 * Tests this axis for equality with an arbitrary object. 713 * 714 * @param obj the object (<code>null</code> permitted). 715 * 716 * @return A boolean. 717 */ 718 public boolean equals(Object obj) { 719 if (obj == this) { 720 return true; 721 } 722 if (!(obj instanceof SymbolAxis)) { 723 return false; 724 } 725 SymbolAxis that = (SymbolAxis) obj; 726 if (!this.symbols.equals(that.symbols)) { 727 return false; 728 } 729 if (this.gridBandsVisible != that.gridBandsVisible) { 730 return false; 731 } 732 if (!PaintUtilities.equal(this.gridBandPaint, that.gridBandPaint)) { 733 return false; 734 } 735 if (!super.equals(obj)) { 736 return false; 737 } 738 return true; 739 } 740 741 /** 742 * Provides serialization support. 743 * 744 * @param stream the output stream. 745 * 746 * @throws IOException if there is an I/O error. 747 */ 748 private void writeObject(ObjectOutputStream stream) throws IOException { 749 stream.defaultWriteObject(); 750 SerialUtilities.writePaint(this.gridBandPaint, stream); 751 } 752 753 /** 754 * Provides serialization support. 755 * 756 * @param stream the input stream. 757 * 758 * @throws IOException if there is an I/O error. 759 * @throws ClassNotFoundException if there is a classpath problem. 760 */ 761 private void readObject(ObjectInputStream stream) 762 throws IOException, ClassNotFoundException { 763 stream.defaultReadObject(); 764 this.gridBandPaint = SerialUtilities.readPaint(stream); 765 } 766 767 }