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