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: * LineAndShapeRenderer.java 29: * ------------------------- 30: * (C) Copyright 2001-2006, by Object Refinery Limited and Contributors. 31: * 32: * Original Author: David Gilbert (for Object Refinery Limited); 33: * Contributor(s): Mark Watson (www.markwatson.com); 34: * Jeremy Bowman; 35: * Richard Atkinson; 36: * Christian W. Zuckschwerdt; 37: * 38: * $Id: LineAndShapeRenderer.java,v 1.18.2.7 2006/10/06 15:02:16 mungady Exp $ 39: * 40: * Changes 41: * ------- 42: * 23-Oct-2001 : Version 1 (DG); 43: * 15-Nov-2001 : Modified to allow for null data values (DG); 44: * 16-Jan-2002 : Renamed HorizontalCategoryItemRenderer.java 45: * --> CategoryItemRenderer.java (DG); 46: * 05-Feb-2002 : Changed return type of the drawCategoryItem method from void 47: * to Shape, as part of the tooltips implementation (DG); 48: * 11-May-2002 : Support for value label drawing (JB); 49: * 29-May-2002 : Now extends AbstractCategoryItemRenderer (DG); 50: * 25-Jun-2002 : Removed redundant import (DG); 51: * 05-Aug-2002 : Small modification to drawCategoryItem method to support URLs 52: * for HTML image maps (RA); 53: * 26-Sep-2002 : Fixed errors reported by Checkstyle (DG); 54: * 11-Oct-2002 : Added new constructor to incorporate tool tip and URL 55: * generators (DG); 56: * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and 57: * CategoryToolTipGenerator interface (DG); 58: * 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG); 59: * 06-Nov-2002 : Renamed drawCategoryItem() --> drawItem() and now using axis 60: * for category spacing (DG); 61: * 17-Jan-2003 : Moved plot classes to a separate package (DG); 62: * 10-Apr-2003 : Changed CategoryDataset to KeyedValues2DDataset in drawItem() 63: * method (DG); 64: * 12-May-2003 : Modified to take into account the plot orientation (DG); 65: * 29-Jul-2003 : Amended code that doesn't compile with JDK 1.2.2 (DG); 66: * 30-Jul-2003 : Modified entity constructor (CZ); 67: * 22-Sep-2003 : Fixed cloning (DG); 68: * 10-Feb-2004 : Small change to drawItem() method to make cut-and-paste 69: * override easier (DG); 70: * 16-Jun-2004 : Fixed bug (id=972454) with label positioning on horizontal 71: * charts (DG); 72: * 15-Oct-2004 : Updated equals() method (DG); 73: * 05-Nov-2004 : Modified drawItem() signature (DG); 74: * 11-Nov-2004 : Now uses ShapeUtilities class to translate shapes (DG); 75: * 27-Jan-2005 : Changed attribute names, modified constructor and removed 76: * constants (DG); 77: * 01-Feb-2005 : Removed unnecessary constants (DG); 78: * 15-Mar-2005 : Fixed bug 1163897, concerning outlines for shapes (DG); 79: * 13-Apr-2005 : Check flags that control series visibility (DG); 80: * 20-Apr-2005 : Use generators for legend labels, tooltips and URLs (DG); 81: * 09-Jun-2005 : Use addItemEntity() method (DG); 82: * ------------- JFREECHART 1.0.x --------------------------------------------- 83: * 25-May-2006 : Added check to drawItem() to detect when both the line and 84: * the shape are not visible (DG); 85: * 86: */ 87: 88: package org.jfree.chart.renderer.category; 89: 90: import java.awt.Graphics2D; 91: import java.awt.Paint; 92: import java.awt.Shape; 93: import java.awt.Stroke; 94: import java.awt.geom.Line2D; 95: import java.awt.geom.Rectangle2D; 96: import java.io.Serializable; 97: 98: import org.jfree.chart.LegendItem; 99: import org.jfree.chart.axis.CategoryAxis; 100: import org.jfree.chart.axis.ValueAxis; 101: import org.jfree.chart.entity.EntityCollection; 102: import org.jfree.chart.event.RendererChangeEvent; 103: import org.jfree.chart.plot.CategoryPlot; 104: import org.jfree.chart.plot.PlotOrientation; 105: import org.jfree.data.category.CategoryDataset; 106: import org.jfree.util.BooleanList; 107: import org.jfree.util.BooleanUtilities; 108: import org.jfree.util.ObjectUtilities; 109: import org.jfree.util.PublicCloneable; 110: import org.jfree.util.ShapeUtilities; 111: 112: /** 113: * A renderer that draws shapes for each data item, and lines between data 114: * items (for use with the {@link CategoryPlot} class). 115: */ 116: public class LineAndShapeRenderer extends AbstractCategoryItemRenderer 117: implements Cloneable, PublicCloneable, 118: Serializable { 119: 120: /** For serialization. */ 121: private static final long serialVersionUID = -197749519869226398L; 122: 123: /** A flag that controls whether or not lines are visible for ALL series. */ 124: private Boolean linesVisible; 125: 126: /** 127: * A table of flags that control (per series) whether or not lines are 128: * visible. 129: */ 130: private BooleanList seriesLinesVisible; 131: 132: /** 133: * A flag indicating whether or not lines are drawn between non-null 134: * points. 135: */ 136: private boolean baseLinesVisible; 137: 138: /** 139: * A flag that controls whether or not shapes are visible for ALL series. 140: */ 141: private Boolean shapesVisible; 142: 143: /** 144: * A table of flags that control (per series) whether or not shapes are 145: * visible. 146: */ 147: private BooleanList seriesShapesVisible; 148: 149: /** The default value returned by the getShapeVisible() method. */ 150: private boolean baseShapesVisible; 151: 152: /** A flag that controls whether or not shapes are filled for ALL series. */ 153: private Boolean shapesFilled; 154: 155: /** 156: * A table of flags that control (per series) whether or not shapes are 157: * filled. 158: */ 159: private BooleanList seriesShapesFilled; 160: 161: /** The default value returned by the getShapeFilled() method. */ 162: private boolean baseShapesFilled; 163: 164: /** 165: * A flag that controls whether the fill paint is used for filling 166: * shapes. 167: */ 168: private boolean useFillPaint; 169: 170: /** A flag that controls whether outlines are drawn for shapes. */ 171: private boolean drawOutlines; 172: 173: /** 174: * A flag that controls whether the outline paint is used for drawing shape 175: * outlines - if not, the regular series paint is used. 176: */ 177: private boolean useOutlinePaint; 178: 179: /** 180: * Creates a renderer with both lines and shapes visible by default. 181: */ 182: public LineAndShapeRenderer() { 183: this(true, true); 184: } 185: 186: /** 187: * Creates a new renderer with lines and/or shapes visible. 188: * 189: * @param lines draw lines? 190: * @param shapes draw shapes? 191: */ 192: public LineAndShapeRenderer(boolean lines, boolean shapes) { 193: super(); 194: this.linesVisible = null; 195: this.seriesLinesVisible = new BooleanList(); 196: this.baseLinesVisible = lines; 197: this.shapesVisible = null; 198: this.seriesShapesVisible = new BooleanList(); 199: this.baseShapesVisible = shapes; 200: this.shapesFilled = null; 201: this.seriesShapesFilled = new BooleanList(); 202: this.baseShapesFilled = true; 203: this.useFillPaint = false; 204: this.drawOutlines = true; 205: this.useOutlinePaint = false; 206: } 207: 208: // LINES VISIBLE 209: 210: /** 211: * Returns the flag used to control whether or not the line for an item is 212: * visible. 213: * 214: * @param series the series index (zero-based). 215: * @param item the item index (zero-based). 216: * 217: * @return A boolean. 218: */ 219: public boolean getItemLineVisible(int series, int item) { 220: Boolean flag = this.linesVisible; 221: if (flag == null) { 222: flag = getSeriesLinesVisible(series); 223: } 224: if (flag != null) { 225: return flag.booleanValue(); 226: } 227: else { 228: return this.baseLinesVisible; 229: } 230: } 231: 232: /** 233: * Returns a flag that controls whether or not lines are drawn for ALL 234: * series. If this flag is <code>null</code>, then the "per series" 235: * settings will apply. 236: * 237: * @return A flag (possibly <code>null</code>). 238: */ 239: public Boolean getLinesVisible() { 240: return this.linesVisible; 241: } 242: 243: /** 244: * Sets a flag that controls whether or not lines are drawn between the 245: * items in ALL series, and sends a {@link RendererChangeEvent} to all 246: * registered listeners. You need to set this to <code>null</code> if you 247: * want the "per series" settings to apply. 248: * 249: * @param visible the flag (<code>null</code> permitted). 250: */ 251: public void setLinesVisible(Boolean visible) { 252: this.linesVisible = visible; 253: notifyListeners(new RendererChangeEvent(this)); 254: } 255: 256: /** 257: * Sets a flag that controls whether or not lines are drawn between the 258: * items in ALL series, and sends a {@link RendererChangeEvent} to all 259: * registered listeners. 260: * 261: * @param visible the flag. 262: */ 263: public void setLinesVisible(boolean visible) { 264: setLinesVisible(BooleanUtilities.valueOf(visible)); 265: } 266: 267: /** 268: * Returns the flag used to control whether or not the lines for a series 269: * are visible. 270: * 271: * @param series the series index (zero-based). 272: * 273: * @return The flag (possibly <code>null</code>). 274: */ 275: public Boolean getSeriesLinesVisible(int series) { 276: return this.seriesLinesVisible.getBoolean(series); 277: } 278: 279: /** 280: * Sets the 'lines visible' flag for a series. 281: * 282: * @param series the series index (zero-based). 283: * @param flag the flag (<code>null</code> permitted). 284: */ 285: public void setSeriesLinesVisible(int series, Boolean flag) { 286: this.seriesLinesVisible.setBoolean(series, flag); 287: notifyListeners(new RendererChangeEvent(this)); 288: } 289: 290: /** 291: * Sets the 'lines visible' flag for a series. 292: * 293: * @param series the series index (zero-based). 294: * @param visible the flag. 295: */ 296: public void setSeriesLinesVisible(int series, boolean visible) { 297: setSeriesLinesVisible(series, BooleanUtilities.valueOf(visible)); 298: } 299: 300: /** 301: * Returns the base 'lines visible' attribute. 302: * 303: * @return The base flag. 304: */ 305: public boolean getBaseLinesVisible() { 306: return this.baseLinesVisible; 307: } 308: 309: /** 310: * Sets the base 'lines visible' flag. 311: * 312: * @param flag the flag. 313: */ 314: public void setBaseLinesVisible(boolean flag) { 315: this.baseLinesVisible = flag; 316: notifyListeners(new RendererChangeEvent(this)); 317: } 318: 319: // SHAPES VISIBLE 320: 321: /** 322: * Returns the flag used to control whether or not the shape for an item is 323: * visible. 324: * 325: * @param series the series index (zero-based). 326: * @param item the item index (zero-based). 327: * 328: * @return A boolean. 329: */ 330: public boolean getItemShapeVisible(int series, int item) { 331: Boolean flag = this.shapesVisible; 332: if (flag == null) { 333: flag = getSeriesShapesVisible(series); 334: } 335: if (flag != null) { 336: return flag.booleanValue(); 337: } 338: else { 339: return this.baseShapesVisible; 340: } 341: } 342: 343: /** 344: * Returns the flag that controls whether the shapes are visible for the 345: * items in ALL series. 346: * 347: * @return The flag (possibly <code>null</code>). 348: */ 349: public Boolean getShapesVisible() { 350: return this.shapesVisible; 351: } 352: 353: /** 354: * Sets the 'shapes visible' for ALL series and sends a 355: * {@link RendererChangeEvent} to all registered listeners. 356: * 357: * @param visible the flag (<code>null</code> permitted). 358: */ 359: public void setShapesVisible(Boolean visible) { 360: this.shapesVisible = visible; 361: notifyListeners(new RendererChangeEvent(this)); 362: } 363: 364: /** 365: * Sets the 'shapes visible' for ALL series and sends a 366: * {@link RendererChangeEvent} to all registered listeners. 367: * 368: * @param visible the flag. 369: */ 370: public void setShapesVisible(boolean visible) { 371: setShapesVisible(BooleanUtilities.valueOf(visible)); 372: } 373: 374: /** 375: * Returns the flag used to control whether or not the shapes for a series 376: * are visible. 377: * 378: * @param series the series index (zero-based). 379: * 380: * @return A boolean. 381: */ 382: public Boolean getSeriesShapesVisible(int series) { 383: return this.seriesShapesVisible.getBoolean(series); 384: } 385: 386: /** 387: * Sets the 'shapes visible' flag for a series and sends a 388: * {@link RendererChangeEvent} to all registered listeners. 389: * 390: * @param series the series index (zero-based). 391: * @param visible the flag. 392: */ 393: public void setSeriesShapesVisible(int series, boolean visible) { 394: setSeriesShapesVisible(series, BooleanUtilities.valueOf(visible)); 395: } 396: 397: /** 398: * Sets the 'shapes visible' flag for a series and sends a 399: * {@link RendererChangeEvent} to all registered listeners. 400: * 401: * @param series the series index (zero-based). 402: * @param flag the flag. 403: */ 404: public void setSeriesShapesVisible(int series, Boolean flag) { 405: this.seriesShapesVisible.setBoolean(series, flag); 406: notifyListeners(new RendererChangeEvent(this)); 407: } 408: 409: /** 410: * Returns the base 'shape visible' attribute. 411: * 412: * @return The base flag. 413: */ 414: public boolean getBaseShapesVisible() { 415: return this.baseShapesVisible; 416: } 417: 418: /** 419: * Sets the base 'shapes visible' flag. 420: * 421: * @param flag the flag. 422: */ 423: public void setBaseShapesVisible(boolean flag) { 424: this.baseShapesVisible = flag; 425: notifyListeners(new RendererChangeEvent(this)); 426: } 427: 428: /** 429: * Returns <code>true</code> if outlines should be drawn for shapes, and 430: * <code>false</code> otherwise. 431: * 432: * @return A boolean. 433: */ 434: public boolean getDrawOutlines() { 435: return this.drawOutlines; 436: } 437: 438: /** 439: * Sets the flag that controls whether outlines are drawn for 440: * shapes, and sends a {@link RendererChangeEvent} to all registered 441: * listeners. 442: * <P> 443: * In some cases, shapes look better if they do NOT have an outline, but 444: * this flag allows you to set your own preference. 445: * 446: * @param flag the flag. 447: */ 448: public void setDrawOutlines(boolean flag) { 449: this.drawOutlines = flag; 450: notifyListeners(new RendererChangeEvent(this)); 451: } 452: 453: /** 454: * Returns the flag that controls whether the outline paint is used for 455: * shape outlines. If not, the regular series paint is used. 456: * 457: * @return A boolean. 458: */ 459: public boolean getUseOutlinePaint() { 460: return this.useOutlinePaint; 461: } 462: 463: /** 464: * Sets the flag that controls whether the outline paint is used for shape 465: * outlines. 466: * 467: * @param use the flag. 468: */ 469: public void setUseOutlinePaint(boolean use) { 470: this.useOutlinePaint = use; 471: } 472: 473: // SHAPES FILLED 474: 475: /** 476: * Returns the flag used to control whether or not the shape for an item 477: * is filled. The default implementation passes control to the 478: * <code>getSeriesShapesFilled</code> method. You can override this method 479: * if you require different behaviour. 480: * 481: * @param series the series index (zero-based). 482: * @param item the item index (zero-based). 483: * 484: * @return A boolean. 485: */ 486: public boolean getItemShapeFilled(int series, int item) { 487: return getSeriesShapesFilled(series); 488: } 489: 490: /** 491: * Returns the flag used to control whether or not the shapes for a series 492: * are filled. 493: * 494: * @param series the series index (zero-based). 495: * 496: * @return A boolean. 497: */ 498: public boolean getSeriesShapesFilled(int series) { 499: 500: // return the overall setting, if there is one... 501: if (this.shapesFilled != null) { 502: return this.shapesFilled.booleanValue(); 503: } 504: 505: // otherwise look up the paint table 506: Boolean flag = this.seriesShapesFilled.getBoolean(series); 507: if (flag != null) { 508: return flag.booleanValue(); 509: } 510: else { 511: return this.baseShapesFilled; 512: } 513: 514: } 515: 516: /** 517: * Returns the flag that controls whether or not shapes are filled for 518: * ALL series. 519: * 520: * @return A Boolean. 521: */ 522: public Boolean getShapesFilled() { 523: return this.shapesFilled; 524: } 525: 526: /** 527: * Sets the 'shapes filled' for ALL series. 528: * 529: * @param filled the flag. 530: */ 531: public void setShapesFilled(boolean filled) { 532: if (filled) { 533: setShapesFilled(Boolean.TRUE); 534: } 535: else { 536: setShapesFilled(Boolean.FALSE); 537: } 538: } 539: 540: /** 541: * Sets the 'shapes filled' for ALL series. 542: * 543: * @param filled the flag (<code>null</code> permitted). 544: */ 545: public void setShapesFilled(Boolean filled) { 546: this.shapesFilled = filled; 547: } 548: 549: /** 550: * Sets the 'shapes filled' flag for a series. 551: * 552: * @param series the series index (zero-based). 553: * @param filled the flag. 554: */ 555: public void setSeriesShapesFilled(int series, Boolean filled) { 556: this.seriesShapesFilled.setBoolean(series, filled); 557: } 558: 559: /** 560: * Sets the 'shapes filled' flag for a series. 561: * 562: * @param series the series index (zero-based). 563: * @param filled the flag. 564: */ 565: public void setSeriesShapesFilled(int series, boolean filled) { 566: this.seriesShapesFilled.setBoolean( 567: series, BooleanUtilities.valueOf(filled) 568: ); 569: } 570: 571: /** 572: * Returns the base 'shape filled' attribute. 573: * 574: * @return The base flag. 575: */ 576: public boolean getBaseShapesFilled() { 577: return this.baseShapesFilled; 578: } 579: 580: /** 581: * Sets the base 'shapes filled' flag. 582: * 583: * @param flag the flag. 584: */ 585: public void setBaseShapesFilled(boolean flag) { 586: this.baseShapesFilled = flag; 587: } 588: 589: /** 590: * Returns <code>true</code> if the renderer should use the fill paint 591: * setting to fill shapes, and <code>false</code> if it should just 592: * use the regular paint. 593: * 594: * @return A boolean. 595: */ 596: public boolean getUseFillPaint() { 597: return this.useFillPaint; 598: } 599: 600: /** 601: * Sets the flag that controls whether the fill paint is used to fill 602: * shapes, and sends a {@link RendererChangeEvent} to all 603: * registered listeners. 604: * 605: * @param flag the flag. 606: */ 607: public void setUseFillPaint(boolean flag) { 608: this.useFillPaint = flag; 609: notifyListeners(new RendererChangeEvent(this)); 610: } 611: 612: /** 613: * Returns a legend item for a series. 614: * 615: * @param datasetIndex the dataset index (zero-based). 616: * @param series the series index (zero-based). 617: * 618: * @return The legend item. 619: */ 620: public LegendItem getLegendItem(int datasetIndex, int series) { 621: 622: CategoryPlot cp = getPlot(); 623: if (cp == null) { 624: return null; 625: } 626: 627: if (isSeriesVisible(series) && isSeriesVisibleInLegend(series)) { 628: CategoryDataset dataset; 629: dataset = cp.getDataset(datasetIndex); 630: String label = getLegendItemLabelGenerator().generateLabel( 631: dataset, series); 632: String description = label; 633: String toolTipText = null; 634: if (getLegendItemToolTipGenerator() != null) { 635: toolTipText = getLegendItemToolTipGenerator().generateLabel( 636: dataset, series); 637: } 638: String urlText = null; 639: if (getLegendItemURLGenerator() != null) { 640: urlText = getLegendItemURLGenerator().generateLabel( 641: dataset, series); 642: } 643: Shape shape = getSeriesShape(series); 644: Paint paint = getSeriesPaint(series); 645: Paint fillPaint = (this.useFillPaint 646: ? getItemFillPaint(series, 0) : paint); 647: boolean shapeOutlineVisible = this.drawOutlines; 648: Paint outlinePaint = (this.useOutlinePaint 649: ? getItemOutlinePaint(series, 0) : paint); 650: Stroke outlineStroke = getSeriesOutlineStroke(series); 651: boolean lineVisible = getItemLineVisible(series, 0); 652: boolean shapeVisible = getItemShapeVisible(series, 0); 653: return new LegendItem(label, description, toolTipText, 654: urlText, shapeVisible, shape, getItemShapeFilled(series, 0), 655: fillPaint, shapeOutlineVisible, outlinePaint, outlineStroke, 656: lineVisible, new Line2D.Double(-7.0, 0.0, 7.0, 0.0), 657: getItemStroke(series, 0), getItemPaint(series, 0)); 658: } 659: return null; 660: 661: } 662: 663: /** 664: * This renderer uses two passes to draw the data. 665: * 666: * @return The pass count (<code>2</code> for this renderer). 667: */ 668: public int getPassCount() { 669: return 2; 670: } 671: 672: /** 673: * Draw a single data item. 674: * 675: * @param g2 the graphics device. 676: * @param state the renderer state. 677: * @param dataArea the area in which the data is drawn. 678: * @param plot the plot. 679: * @param domainAxis the domain axis. 680: * @param rangeAxis the range axis. 681: * @param dataset the dataset. 682: * @param row the row index (zero-based). 683: * @param column the column index (zero-based). 684: * @param pass the pass index. 685: */ 686: public void drawItem(Graphics2D g2, CategoryItemRendererState state, 687: Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis, 688: ValueAxis rangeAxis, CategoryDataset dataset, int row, int column, 689: int pass) { 690: 691: // do nothing if item is not visible 692: if (!getItemVisible(row, column)) { 693: return; 694: } 695: 696: // do nothing if both the line and shape are not visible 697: if (!getItemLineVisible(row, column) 698: && !getItemShapeVisible(row, column)) { 699: return; 700: } 701: 702: // nothing is drawn for null... 703: Number v = dataset.getValue(row, column); 704: if (v == null) { 705: return; 706: } 707: 708: PlotOrientation orientation = plot.getOrientation(); 709: 710: // current data point... 711: double x1 = domainAxis.getCategoryMiddle(column, getColumnCount(), 712: dataArea, plot.getDomainAxisEdge()); 713: double value = v.doubleValue(); 714: double y1 = rangeAxis.valueToJava2D(value, dataArea, 715: plot.getRangeAxisEdge()); 716: 717: if (pass == 0 && getItemLineVisible(row, column)) { 718: if (column != 0) { 719: Number previousValue = dataset.getValue(row, column - 1); 720: if (previousValue != null) { 721: // previous data point... 722: double previous = previousValue.doubleValue(); 723: double x0 = domainAxis.getCategoryMiddle(column - 1, 724: getColumnCount(), dataArea, 725: plot.getDomainAxisEdge()); 726: double y0 = rangeAxis.valueToJava2D(previous, dataArea, 727: plot.getRangeAxisEdge()); 728: 729: Line2D line = null; 730: if (orientation == PlotOrientation.HORIZONTAL) { 731: line = new Line2D.Double(y0, x0, y1, x1); 732: } 733: else if (orientation == PlotOrientation.VERTICAL) { 734: line = new Line2D.Double(x0, y0, x1, y1); 735: } 736: g2.setPaint(getItemPaint(row, column)); 737: g2.setStroke(getItemStroke(row, column)); 738: g2.draw(line); 739: } 740: } 741: } 742: 743: if (pass == 1) { 744: Shape shape = getItemShape(row, column); 745: if (orientation == PlotOrientation.HORIZONTAL) { 746: shape = ShapeUtilities.createTranslatedShape(shape, y1, x1); 747: } 748: else if (orientation == PlotOrientation.VERTICAL) { 749: shape = ShapeUtilities.createTranslatedShape(shape, x1, y1); 750: } 751: 752: if (getItemShapeVisible(row, column)) { 753: if (getItemShapeFilled(row, column)) { 754: if (this.useFillPaint) { 755: g2.setPaint(getItemFillPaint(row, column)); 756: } 757: else { 758: g2.setPaint(getItemPaint(row, column)); 759: } 760: g2.fill(shape); 761: } 762: if (this.drawOutlines) { 763: if (this.useOutlinePaint) { 764: g2.setPaint(getItemOutlinePaint(row, column)); 765: } 766: else { 767: g2.setPaint(getItemPaint(row, column)); 768: } 769: g2.setStroke(getItemOutlineStroke(row, column)); 770: g2.draw(shape); 771: } 772: } 773: 774: // draw the item label if there is one... 775: if (isItemLabelVisible(row, column)) { 776: if (orientation == PlotOrientation.HORIZONTAL) { 777: drawItemLabel(g2, orientation, dataset, row, column, y1, 778: x1, (value < 0.0)); 779: } 780: else if (orientation == PlotOrientation.VERTICAL) { 781: drawItemLabel(g2, orientation, dataset, row, column, x1, 782: y1, (value < 0.0)); 783: } 784: } 785: 786: // add an item entity, if this information is being collected 787: EntityCollection entities = state.getEntityCollection(); 788: if (entities != null) { 789: addItemEntity(entities, dataset, row, column, shape); 790: } 791: } 792: 793: } 794: 795: /** 796: * Tests this renderer for equality with an arbitrary object. 797: * 798: * @param obj the object (<code>null</code> permitted). 799: * 800: * @return A boolean. 801: */ 802: public boolean equals(Object obj) { 803: 804: if (obj == this) { 805: return true; 806: } 807: if (!(obj instanceof LineAndShapeRenderer)) { 808: return false; 809: } 810: 811: LineAndShapeRenderer that = (LineAndShapeRenderer) obj; 812: if (this.baseLinesVisible != that.baseLinesVisible) { 813: return false; 814: } 815: if (!ObjectUtilities.equal(this.seriesLinesVisible, 816: that.seriesLinesVisible)) { 817: return false; 818: } 819: if (!ObjectUtilities.equal(this.linesVisible, that.linesVisible)) { 820: return false; 821: } 822: if (this.baseShapesVisible != that.baseShapesVisible) { 823: return false; 824: } 825: if (!ObjectUtilities.equal(this.seriesShapesVisible, 826: that.seriesShapesVisible)) { 827: return false; 828: } 829: if (!ObjectUtilities.equal(this.shapesVisible, that.shapesVisible)) { 830: return false; 831: } 832: if (!ObjectUtilities.equal(this.shapesFilled, that.shapesFilled)) { 833: return false; 834: } 835: if (!ObjectUtilities.equal(this.seriesShapesFilled, 836: that.seriesShapesFilled)) { 837: return false; 838: } 839: if (this.baseShapesFilled != that.baseShapesFilled) { 840: return false; 841: } 842: if (this.useOutlinePaint != that.useOutlinePaint) { 843: return false; 844: } 845: if (!super.equals(obj)) { 846: return false; 847: } 848: return true; 849: } 850: 851: /** 852: * Returns an independent copy of the renderer. 853: * 854: * @return A clone. 855: * 856: * @throws CloneNotSupportedException should not happen. 857: */ 858: public Object clone() throws CloneNotSupportedException { 859: LineAndShapeRenderer clone = (LineAndShapeRenderer) super.clone(); 860: clone.seriesLinesVisible 861: = (BooleanList) this.seriesLinesVisible.clone(); 862: clone.seriesShapesVisible 863: = (BooleanList) this.seriesLinesVisible.clone(); 864: clone.seriesShapesFilled 865: = (BooleanList) this.seriesShapesFilled.clone(); 866: return clone; 867: } 868: 869: }