001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ------------------------- 028 * LineAndShapeRenderer.java 029 * ------------------------- 030 * (C) Copyright 2001-2006, by Object Refinery Limited and Contributors. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): Mark Watson (www.markwatson.com); 034 * Jeremy Bowman; 035 * Richard Atkinson; 036 * Christian W. Zuckschwerdt; 037 * 038 * $Id: LineAndShapeRenderer.java,v 1.18.2.7 2006/10/06 15:02:16 mungady Exp $ 039 * 040 * Changes 041 * ------- 042 * 23-Oct-2001 : Version 1 (DG); 043 * 15-Nov-2001 : Modified to allow for null data values (DG); 044 * 16-Jan-2002 : Renamed HorizontalCategoryItemRenderer.java 045 * --> CategoryItemRenderer.java (DG); 046 * 05-Feb-2002 : Changed return type of the drawCategoryItem method from void 047 * to Shape, as part of the tooltips implementation (DG); 048 * 11-May-2002 : Support for value label drawing (JB); 049 * 29-May-2002 : Now extends AbstractCategoryItemRenderer (DG); 050 * 25-Jun-2002 : Removed redundant import (DG); 051 * 05-Aug-2002 : Small modification to drawCategoryItem method to support URLs 052 * for HTML image maps (RA); 053 * 26-Sep-2002 : Fixed errors reported by Checkstyle (DG); 054 * 11-Oct-2002 : Added new constructor to incorporate tool tip and URL 055 * generators (DG); 056 * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and 057 * CategoryToolTipGenerator interface (DG); 058 * 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG); 059 * 06-Nov-2002 : Renamed drawCategoryItem() --> drawItem() and now using axis 060 * for category spacing (DG); 061 * 17-Jan-2003 : Moved plot classes to a separate package (DG); 062 * 10-Apr-2003 : Changed CategoryDataset to KeyedValues2DDataset in drawItem() 063 * method (DG); 064 * 12-May-2003 : Modified to take into account the plot orientation (DG); 065 * 29-Jul-2003 : Amended code that doesn't compile with JDK 1.2.2 (DG); 066 * 30-Jul-2003 : Modified entity constructor (CZ); 067 * 22-Sep-2003 : Fixed cloning (DG); 068 * 10-Feb-2004 : Small change to drawItem() method to make cut-and-paste 069 * override easier (DG); 070 * 16-Jun-2004 : Fixed bug (id=972454) with label positioning on horizontal 071 * charts (DG); 072 * 15-Oct-2004 : Updated equals() method (DG); 073 * 05-Nov-2004 : Modified drawItem() signature (DG); 074 * 11-Nov-2004 : Now uses ShapeUtilities class to translate shapes (DG); 075 * 27-Jan-2005 : Changed attribute names, modified constructor and removed 076 * constants (DG); 077 * 01-Feb-2005 : Removed unnecessary constants (DG); 078 * 15-Mar-2005 : Fixed bug 1163897, concerning outlines for shapes (DG); 079 * 13-Apr-2005 : Check flags that control series visibility (DG); 080 * 20-Apr-2005 : Use generators for legend labels, tooltips and URLs (DG); 081 * 09-Jun-2005 : Use addItemEntity() method (DG); 082 * ------------- JFREECHART 1.0.x --------------------------------------------- 083 * 25-May-2006 : Added check to drawItem() to detect when both the line and 084 * the shape are not visible (DG); 085 * 086 */ 087 088 package org.jfree.chart.renderer.category; 089 090 import java.awt.Graphics2D; 091 import java.awt.Paint; 092 import java.awt.Shape; 093 import java.awt.Stroke; 094 import java.awt.geom.Line2D; 095 import java.awt.geom.Rectangle2D; 096 import java.io.Serializable; 097 098 import org.jfree.chart.LegendItem; 099 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 }