001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2011, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * ----------------------------- 028 * DefaultPolarItemRenderer.java 029 * ----------------------------- 030 * (C) Copyright 2004-2011, by Solution Engineering, Inc. and 031 * Contributors. 032 * 033 * Original Author: Daniel Bridenbecker, Solution Engineering, Inc.; 034 * Contributor(s): David Gilbert (for Object Refinery Limited); 035 * Martin Hoeller (patch 2850344); 036 * 037 * Changes 038 * ------- 039 * 19-Jan-2004 : Version 1, contributed by DB with minor changes by DG (DG); 040 * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 041 * getYValue() (DG); 042 * 04-Oct-2004 : Renamed BooleanUtils --> BooleanUtilities (DG); 043 * 20-Apr-2005 : Update for change to LegendItem class (DG); 044 * ------------- JFREECHART 1.0.x --------------------------------------------- 045 * 04-Aug-2006 : Implemented equals() and clone() (DG); 046 * 02-Feb-2007 : Removed author tags from all over JFreeChart sources (DG); 047 * 14-Mar-2007 : Fixed clone() method (DG); 048 * 04-May-2007 : Fixed lookup for series paint and stroke (DG); 049 * 18-May-2007 : Set dataset for LegendItem (DG); 050 * 03-Sep-2009 : Applied patch 2850344 by Martin Hoeller (DG); 051 * 27-Nov-2009 : Updated for modification to PolarItemRenderer interface (DG); 052 * 03-Oct-2011 : Fixed potential NPE in equals() (MH); 053 * 03-Oct-2011 : Added flag to connectFirstAndLastPoint (MH); 054 * 03-Oct-2011 : Added tooltip and URL generator support (MH); 055 * 03-Oct-2011 : Added some configuration options for the legend (MH); 056 * 03-Oct-2011 : Added support for PolarPlot's angleOffset and direction (MH); 057 * 16-Oct-2011 : Fixed serialization problems with fillComposite (MH); 058 */ 059 060package org.jfree.chart.renderer; 061 062import java.awt.AlphaComposite; 063import java.awt.Composite; 064import java.awt.Graphics2D; 065import java.awt.Paint; 066import java.awt.Point; 067import java.awt.Shape; 068import java.awt.Stroke; 069import java.awt.geom.Ellipse2D; 070import java.awt.geom.GeneralPath; 071import java.awt.geom.Line2D; 072import java.awt.geom.PathIterator; 073import java.awt.geom.Rectangle2D; 074import java.io.IOException; 075import java.io.ObjectInputStream; 076import java.io.ObjectOutputStream; 077import java.util.Iterator; 078import java.util.List; 079 080import org.jfree.chart.LegendItem; 081import org.jfree.chart.axis.NumberTick; 082import org.jfree.chart.axis.ValueAxis; 083import org.jfree.chart.entity.EntityCollection; 084import org.jfree.chart.entity.XYItemEntity; 085import org.jfree.chart.event.RendererChangeEvent; 086import org.jfree.chart.labels.XYSeriesLabelGenerator; 087import org.jfree.chart.labels.XYToolTipGenerator; 088import org.jfree.chart.plot.DrawingSupplier; 089import org.jfree.chart.plot.PlotOrientation; 090import org.jfree.chart.plot.PlotRenderingInfo; 091import org.jfree.chart.plot.PolarPlot; 092import org.jfree.chart.renderer.xy.AbstractXYItemRenderer; 093import org.jfree.chart.urls.XYURLGenerator; 094import org.jfree.data.xy.XYDataset; 095import org.jfree.io.SerialUtilities; 096import org.jfree.text.TextUtilities; 097import org.jfree.util.BooleanList; 098import org.jfree.util.BooleanUtilities; 099import org.jfree.util.ObjectList; 100import org.jfree.util.ObjectUtilities; 101import org.jfree.util.PublicCloneable; 102import org.jfree.util.ShapeUtilities; 103 104/** 105 * A renderer that can be used with the {@link PolarPlot} class. 106 */ 107public class DefaultPolarItemRenderer extends AbstractRenderer 108 implements PolarItemRenderer { 109 110 /** The plot that the renderer is assigned to. */ 111 private PolarPlot plot; 112 113 /** Flags that control whether the renderer fills each series or not. */ 114 private BooleanList seriesFilled; 115 116 /** 117 * Flag that controls whether an outline is drawn for filled series or 118 * not. 119 * 120 * @since 1.0.14 121 */ 122 private boolean drawOutlineWhenFilled; 123 124 /** 125 * The composite to use when filling series. 126 * 127 * @since 1.0.14 128 */ 129 private transient Composite fillComposite; 130 131 /** 132 * A flag that controls whether the fill paint is used for filling 133 * shapes. 134 * 135 * @since 1.0.14 136 */ 137 private boolean useFillPaint; 138 139 /** 140 * The shape that is used to represent a line in the legend. 141 * 142 * @since 1.0.14 143 */ 144 private transient Shape legendLine; 145 146 /** 147 * Flag that controls whether item shapes are visible or not. 148 * 149 * @since 1.0.14 150 */ 151 private boolean shapesVisible; 152 153 /** 154 * Flag that controls if the first and last point of the dataset should be 155 * connected or not. 156 * 157 * @since 1.0.14 158 */ 159 private boolean connectFirstAndLastPoint; 160 161 /** 162 * A list of tool tip generators (one per series). 163 * 164 * @since 1.0.14 165 */ 166 private ObjectList toolTipGeneratorList; 167 168 /** 169 * The base tool tip generator. 170 * 171 * @since 1.0.14 172 */ 173 private XYToolTipGenerator baseToolTipGenerator; 174 175 /** 176 * The URL text generator. 177 * 178 * @since 1.0.14 179 */ 180 private XYURLGenerator urlGenerator; 181 182 /** 183 * The legend item tool tip generator. 184 * 185 * @since 1.0.14 186 */ 187 private XYSeriesLabelGenerator legendItemToolTipGenerator; 188 189 /** 190 * The legend item URL generator. 191 * 192 * @since 1.0.14 193 */ 194 private XYSeriesLabelGenerator legendItemURLGenerator; 195 196 197 /** 198 * Creates a new instance of DefaultPolarItemRenderer 199 */ 200 public DefaultPolarItemRenderer() { 201 this.seriesFilled = new BooleanList(); 202 this.drawOutlineWhenFilled = true; 203 this.fillComposite = AlphaComposite.getInstance( 204 AlphaComposite.SRC_OVER, 0.3f); 205 this.useFillPaint = false; // use item paint for fills by default 206 this.legendLine = new Line2D.Double(-7.0, 0.0, 7.0, 0.0); 207 this.shapesVisible = true; 208 this.connectFirstAndLastPoint = true; 209 210 this.toolTipGeneratorList = new ObjectList(); 211 this.urlGenerator = null; 212 this.legendItemToolTipGenerator = null; 213 this.legendItemURLGenerator = null; 214 } 215 216 /** 217 * Set the plot associated with this renderer. 218 * 219 * @param plot the plot. 220 * 221 * @see #getPlot() 222 */ 223 public void setPlot(PolarPlot plot) { 224 this.plot = plot; 225 } 226 227 /** 228 * Return the plot associated with this renderer. 229 * 230 * @return The plot. 231 * 232 * @see #setPlot(PolarPlot) 233 */ 234 public PolarPlot getPlot() { 235 return this.plot; 236 } 237 238 /** 239 * Returns <code>true</code> if the renderer will draw an outline around 240 * a filled polygon, <code>false</code> otherwise. 241 * 242 * @return A boolean. 243 * 244 * @since 1.0.14 245 */ 246 public boolean getDrawOutlineWhenFilled() { 247 return this.drawOutlineWhenFilled; 248 } 249 250 /** 251 * Set the flag that controls whether the outline around a filled 252 * polygon will be drawn or not and sends a {@link RendererChangeEvent} 253 * to all registered listeners. 254 * 255 * @param drawOutlineWhenFilled the flag. 256 * 257 * @since 1.0.14 258 */ 259 public void setDrawOutlineWhenFilled(boolean drawOutlineWhenFilled) { 260 this.drawOutlineWhenFilled = drawOutlineWhenFilled; 261 fireChangeEvent(); 262 } 263 264 /** 265 * Get the composite that is used for filling. 266 * 267 * @return The composite (never <code>null</code>). 268 * 269 * @since 1.0.14 270 */ 271 public Composite getFillComposite() { 272 return this.fillComposite; 273 } 274 275 /** 276 * Set the composite which will be used for filling polygons and sends a 277 * {@link RendererChangeEvent} to all registered listeners. 278 * 279 * @param composite the composite to use (<code>null</code> not 280 * permitted). 281 * 282 * @since 1.0.14 283 */ 284 public void setFillComposite(Composite composite) { 285 if (composite == null) { 286 throw new IllegalArgumentException("Null 'composite' argument."); 287 } 288 this.fillComposite = composite; 289 fireChangeEvent(); 290 } 291 292 /** 293 * Returns <code>true</code> if a shape will be drawn for every item, or 294 * <code>false</code> if not. 295 * 296 * @return A boolean. 297 * 298 * @since 1.0.14 299 */ 300 public boolean getShapesVisible() { 301 return this.shapesVisible; 302 } 303 304 /** 305 * Set the flag that controls whether a shape will be drawn for every 306 * item, or not and sends a {@link RendererChangeEvent} to all registered 307 * listeners. 308 * 309 * @param visible the flag. 310 * 311 * @since 1.0.14 312 */ 313 public void setShapesVisible(boolean visible) { 314 this.shapesVisible = visible; 315 fireChangeEvent(); 316 } 317 318 /** 319 * Returns <code>true</code> if first and last point of a series will be 320 * connected, <code>false</code> otherwise. 321 * 322 * @return The current status of the flag. 323 * 324 * @since 1.0.14 325 */ 326 public boolean getConnectFirstAndLastPoint() { 327 return this.connectFirstAndLastPoint; 328 } 329 330 /** 331 * Set the flag that controls whether the first and last point of a series 332 * will be connected or not and sends a {@link RendererChangeEvent} to all 333 * registered listeners. 334 * 335 * @param connect the flag. 336 * 337 * @since 1.0.14 338 */ 339 public void setConnectFirstAndLastPoint(boolean connect) 340 { 341 this.connectFirstAndLastPoint = connect; 342 fireChangeEvent(); 343 } 344 345 /** 346 * Returns the drawing supplier from the plot. 347 * 348 * @return The drawing supplier. 349 */ 350 public DrawingSupplier getDrawingSupplier() { 351 DrawingSupplier result = null; 352 PolarPlot p = getPlot(); 353 if (p != null) { 354 result = p.getDrawingSupplier(); 355 } 356 return result; 357 } 358 359 /** 360 * Returns <code>true</code> if the renderer should fill the specified 361 * series, and <code>false</code> otherwise. 362 * 363 * @param series the series index (zero-based). 364 * 365 * @return A boolean. 366 */ 367 public boolean isSeriesFilled(int series) { 368 boolean result = false; 369 Boolean b = this.seriesFilled.getBoolean(series); 370 if (b != null) { 371 result = b.booleanValue(); 372 } 373 return result; 374 } 375 376 /** 377 * Sets a flag that controls whether or not a series is filled. 378 * 379 * @param series the series index. 380 * @param filled the flag. 381 */ 382 public void setSeriesFilled(int series, boolean filled) { 383 this.seriesFilled.setBoolean(series, BooleanUtilities.valueOf(filled)); 384 } 385 386 /** 387 * Returns <code>true</code> if the renderer should use the fill paint 388 * setting to fill shapes, and <code>false</code> if it should just 389 * use the regular paint. 390 * 391 * @return A boolean. 392 * 393 * @see #setUseFillPaint(boolean) 394 * @since 1.0.14 395 */ 396 public boolean getUseFillPaint() { 397 return this.useFillPaint; 398 } 399 400 /** 401 * Sets the flag that controls whether the fill paint is used to fill 402 * shapes, and sends a {@link RendererChangeEvent} to all 403 * registered listeners. 404 * 405 * @param flag the flag. 406 * 407 * @see #getUseFillPaint() 408 * @since 1.0.14 409 */ 410 public void setUseFillPaint(boolean flag) { 411 this.useFillPaint = flag; 412 fireChangeEvent(); 413 } 414 415 /** 416 * Returns the shape used to represent a line in the legend. 417 * 418 * @return The legend line (never <code>null</code>). 419 * 420 * @see #setLegendLine(Shape) 421 */ 422 public Shape getLegendLine() { 423 return this.legendLine; 424 } 425 426 /** 427 * Sets the shape used as a line in each legend item and sends a 428 * {@link RendererChangeEvent} to all registered listeners. 429 * 430 * @param line the line (<code>null</code> not permitted). 431 * 432 * @see #getLegendLine() 433 */ 434 public void setLegendLine(Shape line) { 435 if (line == null) { 436 throw new IllegalArgumentException("Null 'line' argument."); 437 } 438 this.legendLine = line; 439 fireChangeEvent(); 440 } 441 442 /** 443 * Adds an entity to the collection. 444 * 445 * @param entities the entity collection being populated. 446 * @param area the entity area (if <code>null</code> a default will be 447 * used). 448 * @param dataset the dataset. 449 * @param series the series. 450 * @param item the item. 451 * @param entityX the entity's center x-coordinate in user space (only 452 * used if <code>area</code> is <code>null</code>). 453 * @param entityY the entity's center y-coordinate in user space (only 454 * used if <code>area</code> is <code>null</code>). 455 */ 456 // this method was copied from AbstractXYItemRenderer on 03-Oct-2011 457 protected void addEntity(EntityCollection entities, Shape area, 458 XYDataset dataset, int series, int item, 459 double entityX, double entityY) { 460 if (!getItemCreateEntity(series, item)) { 461 return; 462 } 463 Shape hotspot = area; 464 if (hotspot == null) { 465 double r = getDefaultEntityRadius(); 466 double w = r * 2; 467 if (getPlot().getOrientation() == PlotOrientation.VERTICAL) { 468 hotspot = new Ellipse2D.Double(entityX - r, entityY - r, w, w); 469 } 470 else { 471 hotspot = new Ellipse2D.Double(entityY - r, entityX - r, w, w); 472 } 473 } 474 String tip = null; 475 XYToolTipGenerator generator = getToolTipGenerator(series, item); 476 if (generator != null) { 477 tip = generator.generateToolTip(dataset, series, item); 478 } 479 String url = null; 480 if (getURLGenerator() != null) { 481 url = getURLGenerator().generateURL(dataset, series, item); 482 } 483 XYItemEntity entity = new XYItemEntity(hotspot, dataset, series, item, 484 tip, url); 485 entities.add(entity); 486 } 487 488 /** 489 * Plots the data for a given series. 490 * 491 * @param g2 the drawing surface. 492 * @param dataArea the data area. 493 * @param info collects plot rendering info. 494 * @param plot the plot. 495 * @param dataset the dataset. 496 * @param seriesIndex the series index. 497 */ 498 public void drawSeries(Graphics2D g2, Rectangle2D dataArea, 499 PlotRenderingInfo info, PolarPlot plot, XYDataset dataset, 500 int seriesIndex) { 501 502 503 GeneralPath poly = null; 504 ValueAxis axis = plot.getAxisForDataset(plot.indexOf(dataset)); 505 final int numPoints = dataset.getItemCount(seriesIndex); 506 for (int i = 0; i < numPoints; i++) { 507 double theta = dataset.getXValue(seriesIndex, i); 508 double radius = dataset.getYValue(seriesIndex, i); 509 Point p = plot.translateToJava2D(theta, radius, axis, dataArea); 510 if (poly == null) { 511 poly = new GeneralPath(); 512 poly.moveTo(p.x, p.y); 513 } 514 else { 515 poly.lineTo(p.x, p.y); 516 } 517 } 518 519 if (getConnectFirstAndLastPoint()) { 520 poly.closePath(); 521 } 522 523 g2.setPaint(lookupSeriesPaint(seriesIndex)); 524 g2.setStroke(lookupSeriesStroke(seriesIndex)); 525 if (isSeriesFilled(seriesIndex)) { 526 Composite savedComposite = g2.getComposite(); 527 g2.setComposite(this.fillComposite); 528 g2.fill(poly); 529 g2.setComposite(savedComposite); 530 if (this.drawOutlineWhenFilled) { 531 // draw the outline of the filled polygon 532 g2.setPaint(lookupSeriesOutlinePaint(seriesIndex)); 533 g2.draw(poly); 534 } 535 } 536 else { 537 // just the lines, no filling 538 g2.draw(poly); 539 } 540 541 // draw the item shapes 542 if (this.shapesVisible) { 543 // setup for collecting optional entity info... 544 EntityCollection entities = null; 545 if (info != null) { 546 entities = info.getOwner().getEntityCollection(); 547 } 548 549 PathIterator pi = poly.getPathIterator(null); 550 int i = 0; 551 while (!pi.isDone()) { 552 final float[] coords = new float[6]; 553 final int segType = pi.currentSegment(coords); 554 pi.next(); 555 if (segType != PathIterator.SEG_LINETO && 556 segType != PathIterator.SEG_MOVETO) 557 continue; 558 final int x = Math.round(coords[0]); 559 final int y = Math.round(coords[1]); 560 final Shape shape = ShapeUtilities.createTranslatedShape( 561 getItemShape(seriesIndex, i++), x, y); 562 563 Paint paint; 564 if (useFillPaint) 565 paint = lookupSeriesFillPaint(seriesIndex); 566 else 567 paint = lookupSeriesPaint(seriesIndex); 568 g2.setPaint(paint); 569 g2.fill(shape); 570 if (isSeriesFilled(seriesIndex) && this.drawOutlineWhenFilled) { 571 g2.setPaint(lookupSeriesOutlinePaint(seriesIndex)); 572 g2.setStroke(lookupSeriesOutlineStroke(seriesIndex)); 573 g2.draw(shape); 574 } 575 576 // add an entity for the item, but only if it falls within the 577 // data area... 578 if (entities != null && 579 AbstractXYItemRenderer.isPointInRect(dataArea, x, y)) { 580 addEntity(entities, shape, dataset, seriesIndex, i-1, x, y); 581 } 582 } 583 } 584 } 585 586 /** 587 * Draw the angular gridlines - the spokes. 588 * 589 * @param g2 the drawing surface. 590 * @param plot the plot. 591 * @param ticks the ticks. 592 * @param dataArea the data area. 593 */ 594 public void drawAngularGridLines(Graphics2D g2, PolarPlot plot, 595 List ticks, Rectangle2D dataArea) { 596 597 g2.setFont(plot.getAngleLabelFont()); 598 g2.setStroke(plot.getAngleGridlineStroke()); 599 g2.setPaint(plot.getAngleGridlinePaint()); 600 601 double axisMin = plot.getAxis().getLowerBound(); 602 double maxRadius = plot.getAxis().getUpperBound(); 603 Point center = plot.translateValueThetaRadiusToJava2D(axisMin, axisMin, 604 dataArea); 605 Iterator iterator = ticks.iterator(); 606 while (iterator.hasNext()) { 607 NumberTick tick = (NumberTick) iterator.next(); 608 double tickVal = tick.getNumber().doubleValue(); 609 Point p = plot.translateValueThetaRadiusToJava2D( 610 tickVal, maxRadius, dataArea); 611 g2.setPaint(plot.getAngleGridlinePaint()); 612 g2.drawLine(center.x, center.y, p.x, p.y); 613 if (plot.isAngleLabelsVisible()) { 614 int x = p.x; 615 int y = p.y; 616 g2.setPaint(plot.getAngleLabelPaint()); 617 TextUtilities.drawAlignedString(tick.getText(), g2, x, y, 618 tick.getTextAnchor()); 619 } 620 } 621 } 622 623 /** 624 * Draw the radial gridlines - the rings. 625 * 626 * @param g2 the drawing surface. 627 * @param plot the plot. 628 * @param radialAxis the radial axis. 629 * @param ticks the ticks. 630 * @param dataArea the data area. 631 */ 632 public void drawRadialGridLines(Graphics2D g2, 633 PolarPlot plot, 634 ValueAxis radialAxis, 635 List ticks, 636 Rectangle2D dataArea) { 637 638 g2.setFont(radialAxis.getTickLabelFont()); 639 g2.setPaint(plot.getRadiusGridlinePaint()); 640 g2.setStroke(plot.getRadiusGridlineStroke()); 641 642 double axisMin = radialAxis.getLowerBound(); 643 Point center = plot.translateValueThetaRadiusToJava2D(axisMin, axisMin, 644 dataArea); 645 646 Iterator iterator = ticks.iterator(); 647 while (iterator.hasNext()) { 648 NumberTick tick = (NumberTick) iterator.next(); 649 double angleDegrees = plot.isCounterClockwise() ? plot.getAngleOffset() : -plot.getAngleOffset(); 650 Point p = plot.translateValueThetaRadiusToJava2D(angleDegrees, 651 tick.getNumber().doubleValue(), dataArea); 652 int r = p.x - center.x; 653 int upperLeftX = center.x - r; 654 int upperLeftY = center.y - r; 655 int d = 2 * r; 656 Ellipse2D ring = new Ellipse2D.Double(upperLeftX, upperLeftY, d, d); 657 g2.setPaint(plot.getRadiusGridlinePaint()); 658 g2.draw(ring); 659 } 660 } 661 662 /** 663 * Return the legend for the given series. 664 * 665 * @param series the series index. 666 * 667 * @return The legend item. 668 */ 669 public LegendItem getLegendItem(int series) { 670 LegendItem result = null; 671 PolarPlot plot = getPlot(); 672 if (plot == null) { 673 return null; 674 } 675 XYDataset dataset = plot.getDataset(plot.getIndexOf(this)); 676 if (dataset == null) { 677 return null; 678 } 679 680 String toolTipText = null; 681 if (getLegendItemToolTipGenerator() != null) { 682 toolTipText = getLegendItemToolTipGenerator().generateLabel( 683 dataset, series); 684 } 685 String urlText = null; 686 if (getLegendItemURLGenerator() != null) { 687 urlText = getLegendItemURLGenerator().generateLabel(dataset, 688 series); 689 } 690 691 String label = dataset.getSeriesKey(series).toString(); 692 String description = label; 693 Shape shape = lookupSeriesShape(series); 694 Paint paint; 695 if (this.useFillPaint) { 696 paint = lookupSeriesFillPaint(series); 697 } 698 else { 699 paint = lookupSeriesPaint(series); 700 } 701 Stroke stroke = lookupSeriesStroke(series); 702 Paint outlinePaint = lookupSeriesOutlinePaint(series); 703 Stroke outlineStroke = lookupSeriesOutlineStroke(series); 704 boolean shapeOutlined = isSeriesFilled(series) 705 && this.drawOutlineWhenFilled; 706 result = new LegendItem(label, description, toolTipText, urlText, 707 getShapesVisible(), shape, /* shapeFilled=*/ true, paint, 708 shapeOutlined, outlinePaint, outlineStroke, 709 /* lineVisible= */ true, this.legendLine, stroke, paint); 710 result.setToolTipText(toolTipText); 711 result.setURLText(urlText); 712 result.setDataset(dataset); 713 714 return result; 715 } 716 717 /** 718 * @since 1.0.14 719 */ 720 public XYToolTipGenerator getToolTipGenerator(int series, int item) 721 { 722 XYToolTipGenerator generator 723 = (XYToolTipGenerator) this.toolTipGeneratorList.get(series); 724 if (generator == null) { 725 generator = this.baseToolTipGenerator; 726 } 727 return generator; 728 } 729 730 /** 731 * @since 1.0.14 732 */ 733 public XYToolTipGenerator getSeriesToolTipGenerator(int series) 734 { 735 return (XYToolTipGenerator) this.toolTipGeneratorList.get(series); 736 } 737 738 /** 739 * @since 1.0.14 740 */ 741 public void setSeriesToolTipGenerator(int series, 742 XYToolTipGenerator generator) 743 { 744 this.toolTipGeneratorList.set(series, generator); 745 fireChangeEvent(); 746 } 747 748 /** 749 * @since 1.0.14 750 */ 751 public XYToolTipGenerator getBaseToolTipGenerator() 752 { 753 return this.baseToolTipGenerator; 754 } 755 756 /** 757 * @since 1.0.14 758 */ 759 public void setBaseToolTipGenerator(XYToolTipGenerator generator) 760 { 761 this.baseToolTipGenerator = generator; 762 fireChangeEvent(); 763 } 764 765 /** 766 * @since 1.0.14 767 */ 768 public XYURLGenerator getURLGenerator() 769 { 770 return this.urlGenerator; 771 } 772 773 /** 774 * @since 1.0.14 775 */ 776 public void setURLGenerator(XYURLGenerator urlGenerator) 777 { 778 this.urlGenerator = urlGenerator; 779 fireChangeEvent(); 780 } 781 782 /** 783 * Returns the legend item tool tip generator. 784 * 785 * @return The tool tip generator (possibly <code>null</code>). 786 * 787 * @see #setLegendItemToolTipGenerator(XYSeriesLabelGenerator) 788 * @since 1.0.14 789 */ 790 public XYSeriesLabelGenerator getLegendItemToolTipGenerator() { 791 return this.legendItemToolTipGenerator; 792 } 793 794 /** 795 * Sets the legend item tool tip generator and sends a 796 * {@link RendererChangeEvent} to all registered listeners. 797 * 798 * @param generator the generator (<code>null</code> permitted). 799 * 800 * @see #getLegendItemToolTipGenerator() 801 * @since 1.0.14 802 */ 803 public void setLegendItemToolTipGenerator( 804 XYSeriesLabelGenerator generator) { 805 this.legendItemToolTipGenerator = generator; 806 fireChangeEvent(); 807 } 808 809 /** 810 * Returns the legend item URL generator. 811 * 812 * @return The URL generator (possibly <code>null</code>). 813 * 814 * @see #setLegendItemURLGenerator(XYSeriesLabelGenerator) 815 * @since 1.0.14 816 */ 817 public XYSeriesLabelGenerator getLegendItemURLGenerator() { 818 return this.legendItemURLGenerator; 819 } 820 821 /** 822 * Sets the legend item URL generator and sends a 823 * {@link RendererChangeEvent} to all registered listeners. 824 * 825 * @param generator the generator (<code>null</code> permitted). 826 * 827 * @see #getLegendItemURLGenerator() 828 * @since 1.0.14 829 */ 830 public void setLegendItemURLGenerator(XYSeriesLabelGenerator generator) { 831 this.legendItemURLGenerator = generator; 832 fireChangeEvent(); 833 } 834 835 /** 836 * Tests this renderer for equality with an arbitrary object. 837 * 838 * @param obj the object (<code>null</code> not permitted). 839 * 840 * @return <code>true</code> if this renderer is equal to <code>obj</code>, 841 * and <code>false</code> otherwise. 842 */ 843 public boolean equals(Object obj) { 844 if (obj == null) { 845 return false; 846 } 847 if (!(obj instanceof DefaultPolarItemRenderer)) { 848 return false; 849 } 850 DefaultPolarItemRenderer that = (DefaultPolarItemRenderer) obj; 851 if (!this.seriesFilled.equals(that.seriesFilled)) { 852 return false; 853 } 854 if (this.drawOutlineWhenFilled != that.drawOutlineWhenFilled) { 855 return false; 856 } 857 if (!ObjectUtilities.equal(this.fillComposite, that.fillComposite)) { 858 return false; 859 } 860 if (this.useFillPaint != that.useFillPaint) { 861 return false; 862 } 863 if (!ShapeUtilities.equal(this.legendLine, that.legendLine)) { 864 return false; 865 } 866 if (this.shapesVisible != that.shapesVisible) { 867 return false; 868 } 869 if (this.connectFirstAndLastPoint != that.connectFirstAndLastPoint) { 870 return false; 871 } 872 if (!this.toolTipGeneratorList.equals(that.toolTipGeneratorList)) { 873 return false; 874 } 875 if (!ObjectUtilities.equal(this.baseToolTipGenerator, 876 that.baseToolTipGenerator)) { 877 return false; 878 } 879 if (!ObjectUtilities.equal(this.urlGenerator, that.urlGenerator)) { 880 return false; 881 } 882 if (!ObjectUtilities.equal(this.legendItemToolTipGenerator, 883 that.legendItemToolTipGenerator)) { 884 return false; 885 } 886 if (!ObjectUtilities.equal(this.legendItemURLGenerator, 887 that.legendItemURLGenerator)) { 888 return false; 889 } 890 return super.equals(obj); 891 } 892 893 /** 894 * Returns a clone of the renderer. 895 * 896 * @return A clone. 897 * 898 * @throws CloneNotSupportedException if the renderer cannot be cloned. 899 */ 900 public Object clone() throws CloneNotSupportedException { 901 DefaultPolarItemRenderer clone 902 = (DefaultPolarItemRenderer) super.clone(); 903 if (this.legendLine != null) { 904 clone.legendLine = ShapeUtilities.clone(this.legendLine); 905 } 906 clone.seriesFilled = (BooleanList) this.seriesFilled.clone(); 907 clone.toolTipGeneratorList 908 = (ObjectList) this.toolTipGeneratorList.clone(); 909 if (clone.baseToolTipGenerator instanceof PublicCloneable) { 910 clone.baseToolTipGenerator = (XYToolTipGenerator) 911 ObjectUtilities.clone(this.baseToolTipGenerator); 912 } 913 if (clone.urlGenerator instanceof PublicCloneable) { 914 clone.urlGenerator = (XYURLGenerator) 915 ObjectUtilities.clone(this.urlGenerator); 916 } 917 if (clone.legendItemToolTipGenerator instanceof PublicCloneable) { 918 clone.legendItemToolTipGenerator = (XYSeriesLabelGenerator) 919 ObjectUtilities.clone(this.legendItemToolTipGenerator); 920 } 921 if (clone.legendItemURLGenerator instanceof PublicCloneable) { 922 clone.legendItemURLGenerator = (XYSeriesLabelGenerator) 923 ObjectUtilities.clone(this.legendItemURLGenerator); 924 } 925 return clone; 926 } 927 928 /** 929 * Provides serialization support. 930 * 931 * @param stream the input stream. 932 * 933 * @throws IOException if there is an I/O error. 934 * @throws ClassNotFoundException if there is a classpath problem. 935 */ 936 private void readObject(ObjectInputStream stream) 937 throws IOException, ClassNotFoundException { 938 stream.defaultReadObject(); 939 this.legendLine = SerialUtilities.readShape(stream); 940 this.fillComposite = SerialUtilities.readComposite(stream); 941 } 942 943 /** 944 * Provides serialization support. 945 * 946 * @param stream the output stream. 947 * 948 * @throws IOException if there is an I/O error. 949 */ 950 private void writeObject(ObjectOutputStream stream) throws IOException { 951 stream.defaultWriteObject(); 952 SerialUtilities.writeShape(this.legendLine, stream); 953 SerialUtilities.writeComposite(this.fillComposite, stream); 954 } 955}