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 * AbstractCategoryItemRenderer.java 029 * --------------------------------- 030 * (C) Copyright 2002-2006, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): Richard Atkinson; 034 * 035 * $Id: AbstractCategoryItemRenderer.java,v 1.17.2.12 2006/12/07 16:52:37 mungady Exp $ 036 * 037 * Changes: 038 * -------- 039 * 29-May-2002 : Version 1 (DG); 040 * 06-Jun-2002 : Added accessor methods for the tool tip generator (DG); 041 * 11-Jun-2002 : Made constructors protected (DG); 042 * 26-Jun-2002 : Added axis to initialise method (DG); 043 * 05-Aug-2002 : Added urlGenerator member variable plus accessors (RA); 044 * 22-Aug-2002 : Added categoriesPaint attribute, based on code submitted by 045 * Janet Banks. This can be used when there is only one series, 046 * and you want each category item to have a different color (DG); 047 * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG); 048 * 29-Oct-2002 : Fixed bug where background image for plot was not being 049 * drawn (DG); 050 * 05-Nov-2002 : Replaced references to CategoryDataset with TableDataset (DG); 051 * 26-Nov 2002 : Replaced the isStacked() method with getRangeType() (DG); 052 * 09-Jan-2003 : Renamed grid-line methods (DG); 053 * 17-Jan-2003 : Moved plot classes into separate package (DG); 054 * 25-Mar-2003 : Implemented Serializable (DG); 055 * 12-May-2003 : Modified to take into account the plot orientation (DG); 056 * 12-Aug-2003 : Very minor javadoc corrections (DB) 057 * 13-Aug-2003 : Implemented Cloneable (DG); 058 * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG); 059 * 05-Nov-2003 : Fixed marker rendering bug (833623) (DG); 060 * 21-Jan-2004 : Update for renamed method in ValueAxis (DG); 061 * 11-Feb-2004 : Modified labelling for markers (DG); 062 * 12-Feb-2004 : Updated clone() method (DG); 063 * 15-Apr-2004 : Created a new CategoryToolTipGenerator interface (DG); 064 * 05-May-2004 : Fixed bug (948310) where interval markers extend outside axis 065 * range (DG); 066 * 14-Jun-2004 : Fixed bug in drawRangeMarker() method - now uses 'paint' and 067 * 'stroke' rather than 'outlinePaint' and 'outlineStroke' (DG); 068 * 15-Jun-2004 : Interval markers can now use GradientPaint (DG); 069 * 30-Sep-2004 : Moved drawRotatedString() from RefineryUtilities 070 * --> TextUtilities (DG); 071 * 01-Oct-2004 : Fixed bug 1029697, problem with label alignment in 072 * drawRangeMarker() method (DG); 073 * 07-Jan-2005 : Renamed getRangeExtent() --> findRangeBounds() (DG); 074 * 21-Jan-2005 : Modified return type of calculateRangeMarkerTextAnchorPoint() 075 * method (DG); 076 * 08-Mar-2005 : Fixed positioning of marker labels (DG); 077 * 20-Apr-2005 : Added legend label, tooltip and URL generators (DG); 078 * 01-Jun-2005 : Handle one dimension of the marker label adjustment 079 * automatically (DG); 080 * 09-Jun-2005 : Added utility method for adding an item entity (DG); 081 * ------------- JFREECHART 1.0.x --------------------------------------------- 082 * 01-Mar-2006 : Updated getLegendItems() to check seriesVisibleInLegend 083 * flags (DG); 084 * 20-Jul-2006 : Set dataset and series indices in LegendItem (DG); 085 * 23-Oct-2006 : Draw outlines for interval markers (DG); 086 * 24-Oct-2006 : Respect alpha setting in markers, as suggested by Sergei 087 * Ivanov in patch 1567843 (DG); 088 * 30-Nov-2006 : Added a check for series visibility in the getLegendItem() 089 * method (DG); 090 * 07-Dec-2006 : Fix for equals() method (DG); 091 * 092 */ 093 094 package org.jfree.chart.renderer.category; 095 096 import java.awt.AlphaComposite; 097 import java.awt.Composite; 098 import java.awt.Font; 099 import java.awt.GradientPaint; 100 import java.awt.Graphics2D; 101 import java.awt.Paint; 102 import java.awt.Shape; 103 import java.awt.Stroke; 104 import java.awt.geom.Line2D; 105 import java.awt.geom.Point2D; 106 import java.awt.geom.Rectangle2D; 107 import java.io.Serializable; 108 109 import org.jfree.chart.LegendItem; 110 import org.jfree.chart.LegendItemCollection; 111 import org.jfree.chart.axis.CategoryAxis; 112 import org.jfree.chart.axis.ValueAxis; 113 import org.jfree.chart.entity.CategoryItemEntity; 114 import org.jfree.chart.entity.EntityCollection; 115 import org.jfree.chart.event.RendererChangeEvent; 116 import org.jfree.chart.labels.CategoryItemLabelGenerator; 117 import org.jfree.chart.labels.CategorySeriesLabelGenerator; 118 import org.jfree.chart.labels.CategoryToolTipGenerator; 119 import org.jfree.chart.labels.ItemLabelPosition; 120 import org.jfree.chart.labels.StandardCategorySeriesLabelGenerator; 121 import org.jfree.chart.plot.CategoryMarker; 122 import org.jfree.chart.plot.CategoryPlot; 123 import org.jfree.chart.plot.DrawingSupplier; 124 import org.jfree.chart.plot.IntervalMarker; 125 import org.jfree.chart.plot.Marker; 126 import org.jfree.chart.plot.PlotOrientation; 127 import org.jfree.chart.plot.PlotRenderingInfo; 128 import org.jfree.chart.plot.ValueMarker; 129 import org.jfree.chart.renderer.AbstractRenderer; 130 import org.jfree.chart.urls.CategoryURLGenerator; 131 import org.jfree.data.Range; 132 import org.jfree.data.category.CategoryDataset; 133 import org.jfree.data.general.DatasetUtilities; 134 import org.jfree.text.TextUtilities; 135 import org.jfree.ui.GradientPaintTransformer; 136 import org.jfree.ui.LengthAdjustmentType; 137 import org.jfree.ui.RectangleAnchor; 138 import org.jfree.ui.RectangleInsets; 139 import org.jfree.util.ObjectList; 140 import org.jfree.util.ObjectUtilities; 141 import org.jfree.util.PublicCloneable; 142 143 /** 144 * An abstract base class that you can use to implement a new 145 * {@link CategoryItemRenderer}. When you create a new 146 * {@link CategoryItemRenderer} you are not required to extend this class, 147 * but it makes the job easier. 148 */ 149 public abstract class AbstractCategoryItemRenderer extends AbstractRenderer 150 implements CategoryItemRenderer, Cloneable, PublicCloneable, Serializable { 151 152 /** For serialization. */ 153 private static final long serialVersionUID = 1247553218442497391L; 154 155 /** The plot that the renderer is assigned to. */ 156 private CategoryPlot plot; 157 158 /** The item label generator for ALL series. */ 159 private CategoryItemLabelGenerator itemLabelGenerator; 160 161 /** A list of item label generators (one per series). */ 162 private ObjectList itemLabelGeneratorList; 163 164 /** The base item label generator. */ 165 private CategoryItemLabelGenerator baseItemLabelGenerator; 166 167 /** The tool tip generator for ALL series. */ 168 private CategoryToolTipGenerator toolTipGenerator; 169 170 /** A list of tool tip generators (one per series). */ 171 private ObjectList toolTipGeneratorList; 172 173 /** The base tool tip generator. */ 174 private CategoryToolTipGenerator baseToolTipGenerator; 175 176 /** The URL generator. */ 177 private CategoryURLGenerator itemURLGenerator; 178 179 /** A list of item label generators (one per series). */ 180 private ObjectList itemURLGeneratorList; 181 182 /** The base item label generator. */ 183 private CategoryURLGenerator baseItemURLGenerator; 184 185 /** The legend item label generator. */ 186 private CategorySeriesLabelGenerator legendItemLabelGenerator; 187 188 /** The legend item tool tip generator. */ 189 private CategorySeriesLabelGenerator legendItemToolTipGenerator; 190 191 /** The legend item URL generator. */ 192 private CategorySeriesLabelGenerator legendItemURLGenerator; 193 194 /** The number of rows in the dataset (temporary record). */ 195 private transient int rowCount; 196 197 /** The number of columns in the dataset (temporary record). */ 198 private transient int columnCount; 199 200 /** 201 * Creates a new renderer with no tool tip generator and no URL generator. 202 * The defaults (no tool tip or URL generators) have been chosen to 203 * minimise the processing required to generate a default chart. If you 204 * require tool tips or URLs, then you can easily add the required 205 * generators. 206 */ 207 protected AbstractCategoryItemRenderer() { 208 this.itemLabelGenerator = null; 209 this.itemLabelGeneratorList = new ObjectList(); 210 this.toolTipGenerator = null; 211 this.toolTipGeneratorList = new ObjectList(); 212 this.itemURLGenerator = null; 213 this.itemURLGeneratorList = new ObjectList(); 214 this.legendItemLabelGenerator 215 = new StandardCategorySeriesLabelGenerator(); 216 } 217 218 /** 219 * Returns the number of passes through the dataset required by the 220 * renderer. This method returns <code>1</code>, subclasses should 221 * override if they need more passes. 222 * 223 * @return The pass count. 224 */ 225 public int getPassCount() { 226 return 1; 227 } 228 229 /** 230 * Returns the plot that the renderer has been assigned to (where 231 * <code>null</code> indicates that the renderer is not currently assigned 232 * to a plot). 233 * 234 * @return The plot (possibly <code>null</code>). 235 */ 236 public CategoryPlot getPlot() { 237 return this.plot; 238 } 239 240 /** 241 * Sets the plot that the renderer has been assigned to. This method is 242 * usually called by the {@link CategoryPlot}, in normal usage you 243 * shouldn't need to call this method directly. 244 * 245 * @param plot the plot (<code>null</code> not permitted). 246 */ 247 public void setPlot(CategoryPlot plot) { 248 if (plot == null) { 249 throw new IllegalArgumentException("Null 'plot' argument."); 250 } 251 this.plot = plot; 252 } 253 254 // ITEM LABEL GENERATOR 255 256 /** 257 * Returns the item label generator for a data item. This implementation 258 * simply passes control to the {@link #getSeriesItemLabelGenerator(int)} 259 * method. If, for some reason, you want a different generator for 260 * individual items, you can override this method. 261 * 262 * @param row the row index (zero based). 263 * @param column the column index (zero based). 264 * 265 * @return The generator (possibly <code>null</code>). 266 */ 267 public CategoryItemLabelGenerator getItemLabelGenerator(int row, 268 int column) { 269 return getSeriesItemLabelGenerator(row); 270 } 271 272 /** 273 * Returns the item label generator for a series. 274 * 275 * @param series the series index (zero based). 276 * 277 * @return The generator (possibly <code>null</code>). 278 */ 279 public CategoryItemLabelGenerator getSeriesItemLabelGenerator(int series) { 280 281 // return the generator for ALL series, if there is one... 282 if (this.itemLabelGenerator != null) { 283 return this.itemLabelGenerator; 284 } 285 286 // otherwise look up the generator table 287 CategoryItemLabelGenerator generator = (CategoryItemLabelGenerator) 288 this.itemLabelGeneratorList.get(series); 289 if (generator == null) { 290 generator = this.baseItemLabelGenerator; 291 } 292 return generator; 293 294 } 295 296 /** 297 * Sets the item label generator for ALL series and sends a 298 * {@link RendererChangeEvent} to all registered listeners. 299 * 300 * @param generator the generator (<code>null</code> permitted). 301 */ 302 public void setItemLabelGenerator(CategoryItemLabelGenerator generator) { 303 this.itemLabelGenerator = generator; 304 notifyListeners(new RendererChangeEvent(this)); 305 } 306 307 /** 308 * Sets the item label generator for a series and sends a 309 * {@link RendererChangeEvent} to all registered listeners. 310 * 311 * @param series the series index (zero based). 312 * @param generator the generator (<code>null</code> permitted). 313 */ 314 public void setSeriesItemLabelGenerator(int series, 315 CategoryItemLabelGenerator generator) { 316 this.itemLabelGeneratorList.set(series, generator); 317 notifyListeners(new RendererChangeEvent(this)); 318 } 319 320 /** 321 * Returns the base item label generator. 322 * 323 * @return The generator (possibly <code>null</code>). 324 */ 325 public CategoryItemLabelGenerator getBaseItemLabelGenerator() { 326 return this.baseItemLabelGenerator; 327 } 328 329 /** 330 * Sets the base item label generator and sends a 331 * {@link RendererChangeEvent} to all registered listeners. 332 * 333 * @param generator the generator (<code>null</code> permitted). 334 */ 335 public void setBaseItemLabelGenerator(CategoryItemLabelGenerator generator) 336 { 337 this.baseItemLabelGenerator = generator; 338 notifyListeners(new RendererChangeEvent(this)); 339 } 340 341 // TOOL TIP GENERATOR 342 343 /** 344 * Returns the tool tip generator that should be used for the specified 345 * item. This method looks up the generator using the "three-layer" 346 * approach outlined in the general description of this interface. You 347 * can override this method if you want to return a different generator per 348 * item. 349 * 350 * @param row the row index (zero-based). 351 * @param column the column index (zero-based). 352 * 353 * @return The generator (possibly <code>null</code>). 354 */ 355 public CategoryToolTipGenerator getToolTipGenerator(int row, int column) { 356 357 CategoryToolTipGenerator result = null; 358 if (this.toolTipGenerator != null) { 359 result = this.toolTipGenerator; 360 } 361 else { 362 result = getSeriesToolTipGenerator(row); 363 if (result == null) { 364 result = this.baseToolTipGenerator; 365 } 366 } 367 return result; 368 } 369 370 /** 371 * Returns the tool tip generator that will be used for ALL items in the 372 * dataset (the "layer 0" generator). 373 * 374 * @return A tool tip generator (possibly <code>null</code>). 375 */ 376 public CategoryToolTipGenerator getToolTipGenerator() { 377 return this.toolTipGenerator; 378 } 379 380 /** 381 * Sets the tool tip generator for ALL series and sends a 382 * {@link org.jfree.chart.event.RendererChangeEvent} to all registered 383 * listeners. 384 * 385 * @param generator the generator (<code>null</code> permitted). 386 */ 387 public void setToolTipGenerator(CategoryToolTipGenerator generator) { 388 this.toolTipGenerator = generator; 389 notifyListeners(new RendererChangeEvent(this)); 390 } 391 392 /** 393 * Returns the tool tip generator for the specified series (a "layer 1" 394 * generator). 395 * 396 * @param series the series index (zero-based). 397 * 398 * @return The tool tip generator (possibly <code>null</code>). 399 */ 400 public CategoryToolTipGenerator getSeriesToolTipGenerator(int series) { 401 return (CategoryToolTipGenerator) this.toolTipGeneratorList.get(series); 402 } 403 404 /** 405 * Sets the tool tip generator for a series and sends a 406 * {@link org.jfree.chart.event.RendererChangeEvent} to all registered 407 * listeners. 408 * 409 * @param series the series index (zero-based). 410 * @param generator the generator (<code>null</code> permitted). 411 */ 412 public void setSeriesToolTipGenerator(int series, 413 CategoryToolTipGenerator generator) { 414 this.toolTipGeneratorList.set(series, generator); 415 notifyListeners(new RendererChangeEvent(this)); 416 } 417 418 /** 419 * Returns the base tool tip generator (the "layer 2" generator). 420 * 421 * @return The tool tip generator (possibly <code>null</code>). 422 */ 423 public CategoryToolTipGenerator getBaseToolTipGenerator() { 424 return this.baseToolTipGenerator; 425 } 426 427 /** 428 * Sets the base tool tip generator and sends a 429 * {@link org.jfree.chart.event.RendererChangeEvent} to all registered 430 * listeners. 431 * 432 * @param generator the generator (<code>null</code> permitted). 433 */ 434 public void setBaseToolTipGenerator(CategoryToolTipGenerator generator) { 435 this.baseToolTipGenerator = generator; 436 notifyListeners(new RendererChangeEvent(this)); 437 } 438 439 // URL GENERATOR 440 441 /** 442 * Returns the URL generator for a data item. This method just calls the 443 * getSeriesItemURLGenerator method, but you can override this behaviour if 444 * you want to. 445 * 446 * @param row the row index (zero based). 447 * @param column the column index (zero based). 448 * 449 * @return The URL generator. 450 */ 451 public CategoryURLGenerator getItemURLGenerator(int row, int column) { 452 return getSeriesItemURLGenerator(row); 453 } 454 455 /** 456 * Returns the URL generator for a series. 457 * 458 * @param series the series index (zero based). 459 * 460 * @return The URL generator for the series. 461 */ 462 public CategoryURLGenerator getSeriesItemURLGenerator(int series) { 463 464 // return the generator for ALL series, if there is one... 465 if (this.itemURLGenerator != null) { 466 return this.itemURLGenerator; 467 } 468 469 // otherwise look up the generator table 470 CategoryURLGenerator generator 471 = (CategoryURLGenerator) this.itemURLGeneratorList.get(series); 472 if (generator == null) { 473 generator = this.baseItemURLGenerator; 474 } 475 return generator; 476 477 } 478 479 /** 480 * Sets the item URL generator for ALL series. 481 * 482 * @param generator the generator. 483 */ 484 public void setItemURLGenerator(CategoryURLGenerator generator) { 485 this.itemURLGenerator = generator; 486 } 487 488 /** 489 * Sets the URL generator for a series. 490 * 491 * @param series the series index (zero based). 492 * @param generator the generator. 493 */ 494 public void setSeriesItemURLGenerator(int series, 495 CategoryURLGenerator generator) { 496 this.itemURLGeneratorList.set(series, generator); 497 } 498 499 /** 500 * Returns the base item URL generator. 501 * 502 * @return The item URL generator. 503 */ 504 public CategoryURLGenerator getBaseItemURLGenerator() { 505 return this.baseItemURLGenerator; 506 } 507 508 /** 509 * Sets the base item URL generator. 510 * 511 * @param generator the item URL generator. 512 */ 513 public void setBaseItemURLGenerator(CategoryURLGenerator generator) { 514 this.baseItemURLGenerator = generator; 515 } 516 517 /** 518 * Returns the number of rows in the dataset. This value is updated in the 519 * {@link AbstractCategoryItemRenderer#initialise} method. 520 * 521 * @return The row count. 522 */ 523 public int getRowCount() { 524 return this.rowCount; 525 } 526 527 /** 528 * Returns the number of columns in the dataset. This value is updated in 529 * the {@link AbstractCategoryItemRenderer#initialise} method. 530 * 531 * @return The column count. 532 */ 533 public int getColumnCount() { 534 return this.columnCount; 535 } 536 537 /** 538 * Initialises the renderer and returns a state object that will be used 539 * for the remainder of the drawing process for a single chart. The state 540 * object allows for the fact that the renderer may be used simultaneously 541 * by multiple threads (each thread will work with a separate state object). 542 * <P> 543 * Stores a reference to the {@link PlotRenderingInfo} object (which might 544 * be <code>null</code>), and then sets the useCategoriesPaint flag 545 * according to the special case conditions a) there is only one series 546 * and b) the categoriesPaint array is not null. 547 * 548 * @param g2 the graphics device. 549 * @param dataArea the data area. 550 * @param plot the plot. 551 * @param rendererIndex the renderer index. 552 * @param info an object for returning information about the structure of 553 * the plot (<code>null</code> permitted). 554 * 555 * @return The renderer state. 556 * 557 */ 558 public CategoryItemRendererState initialise(Graphics2D g2, 559 Rectangle2D dataArea, 560 CategoryPlot plot, 561 int rendererIndex, 562 PlotRenderingInfo info) { 563 564 setPlot(plot); 565 CategoryDataset data = plot.getDataset(rendererIndex); 566 if (data != null) { 567 this.rowCount = data.getRowCount(); 568 this.columnCount = data.getColumnCount(); 569 } 570 else { 571 this.rowCount = 0; 572 this.columnCount = 0; 573 } 574 return new CategoryItemRendererState(info); 575 576 } 577 578 /** 579 * Returns the range of values the renderer requires to display all the 580 * items from the specified dataset. 581 * 582 * @param dataset the dataset (<code>null</code> permitted). 583 * 584 * @return The range (or <code>null</code> if the dataset is 585 * <code>null</code> or empty). 586 */ 587 public Range findRangeBounds(CategoryDataset dataset) { 588 return DatasetUtilities.findRangeBounds(dataset); 589 } 590 591 /** 592 * Draws a background for the data area. The default implementation just 593 * gets the plot to draw the outline, but some renderers will override this 594 * behaviour. 595 * 596 * @param g2 the graphics device. 597 * @param plot the plot. 598 * @param dataArea the data area. 599 */ 600 public void drawBackground(Graphics2D g2, 601 CategoryPlot plot, 602 Rectangle2D dataArea) { 603 604 plot.drawBackground(g2, dataArea); 605 606 } 607 608 /** 609 * Draws an outline for the data area. The default implementation just 610 * gets the plot to draw the outline, but some renderers will override this 611 * behaviour. 612 * 613 * @param g2 the graphics device. 614 * @param plot the plot. 615 * @param dataArea the data area. 616 */ 617 public void drawOutline(Graphics2D g2, 618 CategoryPlot plot, 619 Rectangle2D dataArea) { 620 621 plot.drawOutline(g2, dataArea); 622 623 } 624 625 /** 626 * Draws a grid line against the domain axis. 627 * <P> 628 * Note that this default implementation assumes that the horizontal axis 629 * is the domain axis. If this is not the case, you will need to override 630 * this method. 631 * 632 * @param g2 the graphics device. 633 * @param plot the plot. 634 * @param dataArea the area for plotting data (not yet adjusted for any 635 * 3D effect). 636 * @param value the Java2D value at which the grid line should be drawn. 637 */ 638 public void drawDomainGridline(Graphics2D g2, 639 CategoryPlot plot, 640 Rectangle2D dataArea, 641 double value) { 642 643 Line2D line = null; 644 PlotOrientation orientation = plot.getOrientation(); 645 646 if (orientation == PlotOrientation.HORIZONTAL) { 647 line = new Line2D.Double(dataArea.getMinX(), value, 648 dataArea.getMaxX(), value); 649 } 650 else if (orientation == PlotOrientation.VERTICAL) { 651 line = new Line2D.Double(value, dataArea.getMinY(), value, 652 dataArea.getMaxY()); 653 } 654 655 Paint paint = plot.getDomainGridlinePaint(); 656 if (paint == null) { 657 paint = CategoryPlot.DEFAULT_GRIDLINE_PAINT; 658 } 659 g2.setPaint(paint); 660 661 Stroke stroke = plot.getDomainGridlineStroke(); 662 if (stroke == null) { 663 stroke = CategoryPlot.DEFAULT_GRIDLINE_STROKE; 664 } 665 g2.setStroke(stroke); 666 667 g2.draw(line); 668 669 } 670 671 /** 672 * Draws a grid line against the range axis. 673 * 674 * @param g2 the graphics device. 675 * @param plot the plot. 676 * @param axis the value axis. 677 * @param dataArea the area for plotting data (not yet adjusted for any 678 * 3D effect). 679 * @param value the value at which the grid line should be drawn. 680 * 681 */ 682 public void drawRangeGridline(Graphics2D g2, 683 CategoryPlot plot, 684 ValueAxis axis, 685 Rectangle2D dataArea, 686 double value) { 687 688 Range range = axis.getRange(); 689 if (!range.contains(value)) { 690 return; 691 } 692 693 PlotOrientation orientation = plot.getOrientation(); 694 double v = axis.valueToJava2D(value, dataArea, plot.getRangeAxisEdge()); 695 Line2D line = null; 696 if (orientation == PlotOrientation.HORIZONTAL) { 697 line = new Line2D.Double(v, dataArea.getMinY(), v, 698 dataArea.getMaxY()); 699 } 700 else if (orientation == PlotOrientation.VERTICAL) { 701 line = new Line2D.Double(dataArea.getMinX(), v, 702 dataArea.getMaxX(), v); 703 } 704 705 Paint paint = plot.getRangeGridlinePaint(); 706 if (paint == null) { 707 paint = CategoryPlot.DEFAULT_GRIDLINE_PAINT; 708 } 709 g2.setPaint(paint); 710 711 Stroke stroke = plot.getRangeGridlineStroke(); 712 if (stroke == null) { 713 stroke = CategoryPlot.DEFAULT_GRIDLINE_STROKE; 714 } 715 g2.setStroke(stroke); 716 717 g2.draw(line); 718 719 } 720 721 /** 722 * Draws a marker for the domain axis. 723 * 724 * @param g2 the graphics device (not <code>null</code>). 725 * @param plot the plot (not <code>null</code>). 726 * @param axis the range axis (not <code>null</code>). 727 * @param marker the marker to be drawn (not <code>null</code>). 728 * @param dataArea the area inside the axes (not <code>null</code>). 729 */ 730 public void drawDomainMarker(Graphics2D g2, 731 CategoryPlot plot, 732 CategoryAxis axis, 733 CategoryMarker marker, 734 Rectangle2D dataArea) { 735 736 Comparable category = marker.getKey(); 737 CategoryDataset dataset = plot.getDataset(plot.getIndexOf(this)); 738 int columnIndex = dataset.getColumnIndex(category); 739 if (columnIndex < 0) { 740 return; 741 } 742 743 final Composite savedComposite = g2.getComposite(); 744 g2.setComposite(AlphaComposite.getInstance( 745 AlphaComposite.SRC_OVER, marker.getAlpha())); 746 747 PlotOrientation orientation = plot.getOrientation(); 748 Rectangle2D bounds = null; 749 if (marker.getDrawAsLine()) { 750 double v = axis.getCategoryMiddle(columnIndex, 751 dataset.getColumnCount(), dataArea, 752 plot.getDomainAxisEdge()); 753 Line2D line = null; 754 if (orientation == PlotOrientation.HORIZONTAL) { 755 line = new Line2D.Double(dataArea.getMinX(), v, 756 dataArea.getMaxX(), v); 757 } 758 else if (orientation == PlotOrientation.VERTICAL) { 759 line = new Line2D.Double(v, dataArea.getMinY(), v, 760 dataArea.getMaxY()); 761 } 762 g2.setPaint(marker.getPaint()); 763 g2.setStroke(marker.getStroke()); 764 g2.draw(line); 765 bounds = line.getBounds2D(); 766 } 767 else { 768 double v0 = axis.getCategoryStart(columnIndex, 769 dataset.getColumnCount(), dataArea, 770 plot.getDomainAxisEdge()); 771 double v1 = axis.getCategoryEnd(columnIndex, 772 dataset.getColumnCount(), dataArea, 773 plot.getDomainAxisEdge()); 774 Rectangle2D area = null; 775 if (orientation == PlotOrientation.HORIZONTAL) { 776 area = new Rectangle2D.Double(dataArea.getMinX(), v0, 777 dataArea.getWidth(), (v1 - v0)); 778 } 779 else if (orientation == PlotOrientation.VERTICAL) { 780 area = new Rectangle2D.Double(v0, dataArea.getMinY(), 781 (v1 - v0), dataArea.getHeight()); 782 } 783 g2.setPaint(marker.getPaint()); 784 g2.fill(area); 785 bounds = area; 786 } 787 788 String label = marker.getLabel(); 789 RectangleAnchor anchor = marker.getLabelAnchor(); 790 if (label != null) { 791 Font labelFont = marker.getLabelFont(); 792 g2.setFont(labelFont); 793 g2.setPaint(marker.getLabelPaint()); 794 Point2D coordinates = calculateDomainMarkerTextAnchorPoint( 795 g2, orientation, dataArea, bounds, marker.getLabelOffset(), 796 marker.getLabelOffsetType(), anchor); 797 TextUtilities.drawAlignedString(label, g2, 798 (float) coordinates.getX(), (float) coordinates.getY(), 799 marker.getLabelTextAnchor()); 800 } 801 g2.setComposite(savedComposite); 802 } 803 804 /** 805 * Draws a marker for the range axis. 806 * 807 * @param g2 the graphics device (not <code>null</code>). 808 * @param plot the plot (not <code>null</code>). 809 * @param axis the range axis (not <code>null</code>). 810 * @param marker the marker to be drawn (not <code>null</code>). 811 * @param dataArea the area inside the axes (not <code>null</code>). 812 */ 813 public void drawRangeMarker(Graphics2D g2, 814 CategoryPlot plot, 815 ValueAxis axis, 816 Marker marker, 817 Rectangle2D dataArea) { 818 819 if (marker instanceof ValueMarker) { 820 ValueMarker vm = (ValueMarker) marker; 821 double value = vm.getValue(); 822 Range range = axis.getRange(); 823 824 if (!range.contains(value)) { 825 return; 826 } 827 828 final Composite savedComposite = g2.getComposite(); 829 g2.setComposite(AlphaComposite.getInstance( 830 AlphaComposite.SRC_OVER, marker.getAlpha())); 831 832 PlotOrientation orientation = plot.getOrientation(); 833 double v = axis.valueToJava2D(value, dataArea, 834 plot.getRangeAxisEdge()); 835 Line2D line = null; 836 if (orientation == PlotOrientation.HORIZONTAL) { 837 line = new Line2D.Double(v, dataArea.getMinY(), v, 838 dataArea.getMaxY()); 839 } 840 else if (orientation == PlotOrientation.VERTICAL) { 841 line = new Line2D.Double(dataArea.getMinX(), v, 842 dataArea.getMaxX(), v); 843 } 844 845 g2.setPaint(marker.getPaint()); 846 g2.setStroke(marker.getStroke()); 847 g2.draw(line); 848 849 String label = marker.getLabel(); 850 RectangleAnchor anchor = marker.getLabelAnchor(); 851 if (label != null) { 852 Font labelFont = marker.getLabelFont(); 853 g2.setFont(labelFont); 854 g2.setPaint(marker.getLabelPaint()); 855 Point2D coordinates = calculateRangeMarkerTextAnchorPoint( 856 g2, orientation, dataArea, line.getBounds2D(), 857 marker.getLabelOffset(), LengthAdjustmentType.EXPAND, 858 anchor); 859 TextUtilities.drawAlignedString(label, g2, 860 (float) coordinates.getX(), (float) coordinates.getY(), 861 marker.getLabelTextAnchor()); 862 } 863 g2.setComposite(savedComposite); 864 } 865 else if (marker instanceof IntervalMarker) { 866 867 IntervalMarker im = (IntervalMarker) marker; 868 double start = im.getStartValue(); 869 double end = im.getEndValue(); 870 Range range = axis.getRange(); 871 if (!(range.intersects(start, end))) { 872 return; 873 } 874 875 final Composite savedComposite = g2.getComposite(); 876 g2.setComposite(AlphaComposite.getInstance( 877 AlphaComposite.SRC_OVER, marker.getAlpha())); 878 879 double start2d = axis.valueToJava2D(start, dataArea, 880 plot.getRangeAxisEdge()); 881 double end2d = axis.valueToJava2D(end, dataArea, 882 plot.getRangeAxisEdge()); 883 884 PlotOrientation orientation = plot.getOrientation(); 885 Rectangle2D rect = null; 886 if (orientation == PlotOrientation.HORIZONTAL) { 887 rect = new Rectangle2D.Double(Math.min(start2d, end2d), 888 dataArea.getMinY(), Math.abs(end2d - start2d), 889 dataArea.getHeight()); 890 } 891 else if (orientation == PlotOrientation.VERTICAL) { 892 rect = new Rectangle2D.Double(dataArea.getMinX(), 893 Math.min(start2d, end2d), dataArea.getWidth(), 894 Math.abs(end2d - start2d)); 895 } 896 Paint p = marker.getPaint(); 897 if (p instanceof GradientPaint) { 898 GradientPaint gp = (GradientPaint) p; 899 GradientPaintTransformer t = im.getGradientPaintTransformer(); 900 if (t != null) { 901 gp = t.transform(gp, rect); 902 } 903 g2.setPaint(gp); 904 } 905 else { 906 g2.setPaint(p); 907 } 908 g2.fill(rect); 909 910 // now draw the outlines, if visible... 911 if (im.getOutlinePaint() != null && im.getOutlineStroke() != null) { 912 double x0 = rect.getMinX(); 913 double x1 = rect.getMaxX(); 914 double y0 = rect.getMinY(); 915 double y1 = rect.getMaxY(); 916 if (orientation == PlotOrientation.VERTICAL) { 917 Line2D line = new Line2D.Double(x0, y0, x1, y0); 918 g2.setPaint(im.getOutlinePaint()); 919 g2.setStroke(im.getOutlineStroke()); 920 g2.draw(line); 921 line.setLine(x0, y1, x1, y1); 922 g2.draw(line); 923 } 924 else { // PlotOrientation.HORIZONTAL 925 Line2D line = new Line2D.Double(x0, y0, x0, y1); 926 g2.setPaint(im.getOutlinePaint()); 927 g2.setStroke(im.getOutlineStroke()); 928 g2.draw(line); 929 line.setLine(x1, y0, x1, y1); 930 g2.draw(line); 931 } 932 } 933 934 String label = marker.getLabel(); 935 RectangleAnchor anchor = marker.getLabelAnchor(); 936 if (label != null) { 937 Font labelFont = marker.getLabelFont(); 938 g2.setFont(labelFont); 939 g2.setPaint(marker.getLabelPaint()); 940 Point2D coordinates = calculateRangeMarkerTextAnchorPoint( 941 g2, orientation, dataArea, rect, 942 marker.getLabelOffset(), marker.getLabelOffsetType(), 943 anchor); 944 TextUtilities.drawAlignedString(label, g2, 945 (float) coordinates.getX(), (float) coordinates.getY(), 946 marker.getLabelTextAnchor()); 947 } 948 g2.setComposite(savedComposite); 949 950 } 951 952 } 953 954 /** 955 * Calculates the (x, y) coordinates for drawing the label for a marker on 956 * the range axis. 957 * 958 * @param g2 the graphics device. 959 * @param orientation the plot orientation. 960 * @param dataArea the data area. 961 * @param markerArea the rectangle surrounding the marker. 962 * @param markerOffset the marker offset. 963 * @param labelOffsetType the label offset type. 964 * @param anchor the label anchor. 965 * 966 * @return The coordinates for drawing the marker label. 967 */ 968 protected Point2D calculateDomainMarkerTextAnchorPoint(Graphics2D g2, 969 PlotOrientation orientation, 970 Rectangle2D dataArea, 971 Rectangle2D markerArea, 972 RectangleInsets markerOffset, 973 LengthAdjustmentType labelOffsetType, 974 RectangleAnchor anchor) { 975 976 Rectangle2D anchorRect = null; 977 if (orientation == PlotOrientation.HORIZONTAL) { 978 anchorRect = markerOffset.createAdjustedRectangle(markerArea, 979 LengthAdjustmentType.CONTRACT, labelOffsetType); 980 } 981 else if (orientation == PlotOrientation.VERTICAL) { 982 anchorRect = markerOffset.createAdjustedRectangle(markerArea, 983 labelOffsetType, LengthAdjustmentType.CONTRACT); 984 } 985 return RectangleAnchor.coordinates(anchorRect, anchor); 986 987 } 988 989 /** 990 * Calculates the (x, y) coordinates for drawing a marker label. 991 * 992 * @param g2 the graphics device. 993 * @param orientation the plot orientation. 994 * @param dataArea the data area. 995 * @param markerArea the rectangle surrounding the marker. 996 * @param markerOffset the marker offset. 997 * @param labelOffsetType the label offset type. 998 * @param anchor the label anchor. 999 * 1000 * @return The coordinates for drawing the marker label. 1001 */ 1002 protected Point2D calculateRangeMarkerTextAnchorPoint(Graphics2D g2, 1003 PlotOrientation orientation, 1004 Rectangle2D dataArea, 1005 Rectangle2D markerArea, 1006 RectangleInsets markerOffset, 1007 LengthAdjustmentType labelOffsetType, 1008 RectangleAnchor anchor) { 1009 1010 Rectangle2D anchorRect = null; 1011 if (orientation == PlotOrientation.HORIZONTAL) { 1012 anchorRect = markerOffset.createAdjustedRectangle(markerArea, 1013 labelOffsetType, LengthAdjustmentType.CONTRACT); 1014 } 1015 else if (orientation == PlotOrientation.VERTICAL) { 1016 anchorRect = markerOffset.createAdjustedRectangle(markerArea, 1017 LengthAdjustmentType.CONTRACT, labelOffsetType); 1018 } 1019 return RectangleAnchor.coordinates(anchorRect, anchor); 1020 1021 } 1022 1023 /** 1024 * Returns a legend item for a series. 1025 * 1026 * @param datasetIndex the dataset index (zero-based). 1027 * @param series the series index (zero-based). 1028 * 1029 * @return The legend item. 1030 */ 1031 public LegendItem getLegendItem(int datasetIndex, int series) { 1032 1033 CategoryPlot p = getPlot(); 1034 if (p == null) { 1035 return null; 1036 } 1037 1038 // check that a legend item needs to be displayed... 1039 if (!isSeriesVisible(series) || !isSeriesVisibleInLegend(series)) { 1040 return null; 1041 } 1042 1043 CategoryDataset dataset; 1044 dataset = p.getDataset(datasetIndex); 1045 String label = this.legendItemLabelGenerator.generateLabel(dataset, 1046 series); 1047 String description = label; 1048 String toolTipText = null; 1049 if (this.legendItemToolTipGenerator != null) { 1050 toolTipText = this.legendItemToolTipGenerator.generateLabel( 1051 dataset, series); 1052 } 1053 String urlText = null; 1054 if (this.legendItemURLGenerator != null) { 1055 urlText = this.legendItemURLGenerator.generateLabel(dataset, 1056 series); 1057 } 1058 Shape shape = getSeriesShape(series); 1059 Paint paint = getSeriesPaint(series); 1060 Paint outlinePaint = getSeriesOutlinePaint(series); 1061 Stroke outlineStroke = getSeriesOutlineStroke(series); 1062 1063 LegendItem item = new LegendItem(label, description, toolTipText, 1064 urlText, shape, paint, outlineStroke, outlinePaint); 1065 item.setSeriesIndex(series); 1066 item.setDatasetIndex(datasetIndex); 1067 return item; 1068 } 1069 1070 /** 1071 * Tests this renderer for equality with another object. 1072 * 1073 * @param obj the object. 1074 * 1075 * @return <code>true</code> or <code>false</code>. 1076 */ 1077 public boolean equals(Object obj) { 1078 1079 if (obj == this) { 1080 return true; 1081 } 1082 if (!(obj instanceof AbstractCategoryItemRenderer)) { 1083 return false; 1084 } 1085 AbstractCategoryItemRenderer that = (AbstractCategoryItemRenderer) obj; 1086 1087 if (!ObjectUtilities.equal(this.itemLabelGenerator, 1088 that.itemLabelGenerator)) { 1089 return false; 1090 } 1091 if (!ObjectUtilities.equal(this.itemLabelGeneratorList, 1092 that.itemLabelGeneratorList)) { 1093 return false; 1094 } 1095 if (!ObjectUtilities.equal(this.baseItemLabelGenerator, 1096 that.baseItemLabelGenerator)) { 1097 return false; 1098 } 1099 if (!ObjectUtilities.equal(this.toolTipGenerator, 1100 that.toolTipGenerator)) { 1101 return false; 1102 } 1103 if (!ObjectUtilities.equal(this.toolTipGeneratorList, 1104 that.toolTipGeneratorList)) { 1105 return false; 1106 } 1107 if (!ObjectUtilities.equal(this.baseToolTipGenerator, 1108 that.baseToolTipGenerator)) { 1109 return false; 1110 } 1111 if (!ObjectUtilities.equal(this.itemURLGenerator, 1112 that.itemURLGenerator)) { 1113 return false; 1114 } 1115 if (!ObjectUtilities.equal(this.itemURLGeneratorList, 1116 that.itemURLGeneratorList)) { 1117 return false; 1118 } 1119 if (!ObjectUtilities.equal(this.baseItemURLGenerator, 1120 that.baseItemURLGenerator)) { 1121 return false; 1122 } 1123 if (!ObjectUtilities.equal(this.legendItemLabelGenerator, 1124 that.legendItemLabelGenerator)) { 1125 return false; 1126 } 1127 if (!ObjectUtilities.equal(this.legendItemToolTipGenerator, 1128 that.legendItemToolTipGenerator)) { 1129 return false; 1130 } 1131 if (!ObjectUtilities.equal(this.legendItemURLGenerator, 1132 that.legendItemURLGenerator)) { 1133 return false; 1134 } 1135 return super.equals(obj); 1136 } 1137 1138 /** 1139 * Returns a hash code for the renderer. 1140 * 1141 * @return The hash code. 1142 */ 1143 public int hashCode() { 1144 int result = super.hashCode(); 1145 return result; 1146 } 1147 1148 /** 1149 * Returns the drawing supplier from the plot. 1150 * 1151 * @return The drawing supplier (possibly <code>null</code>). 1152 */ 1153 public DrawingSupplier getDrawingSupplier() { 1154 DrawingSupplier result = null; 1155 CategoryPlot cp = getPlot(); 1156 if (cp != null) { 1157 result = cp.getDrawingSupplier(); 1158 } 1159 return result; 1160 } 1161 1162 /** 1163 * Draws an item label. 1164 * 1165 * @param g2 the graphics device. 1166 * @param orientation the orientation. 1167 * @param dataset the dataset. 1168 * @param row the row. 1169 * @param column the column. 1170 * @param x the x coordinate (in Java2D space). 1171 * @param y the y coordinate (in Java2D space). 1172 * @param negative indicates a negative value (which affects the item 1173 * label position). 1174 */ 1175 protected void drawItemLabel(Graphics2D g2, 1176 PlotOrientation orientation, 1177 CategoryDataset dataset, 1178 int row, int column, 1179 double x, double y, 1180 boolean negative) { 1181 1182 CategoryItemLabelGenerator generator 1183 = getItemLabelGenerator(row, column); 1184 if (generator != null) { 1185 Font labelFont = getItemLabelFont(row, column); 1186 Paint paint = getItemLabelPaint(row, column); 1187 g2.setFont(labelFont); 1188 g2.setPaint(paint); 1189 String label = generator.generateLabel(dataset, row, column); 1190 ItemLabelPosition position = null; 1191 if (!negative) { 1192 position = getPositiveItemLabelPosition(row, column); 1193 } 1194 else { 1195 position = getNegativeItemLabelPosition(row, column); 1196 } 1197 Point2D anchorPoint = calculateLabelAnchorPoint( 1198 position.getItemLabelAnchor(), x, y, orientation); 1199 TextUtilities.drawRotatedString(label, g2, 1200 (float) anchorPoint.getX(), (float) anchorPoint.getY(), 1201 position.getTextAnchor(), 1202 position.getAngle(), position.getRotationAnchor()); 1203 } 1204 1205 } 1206 1207 /** 1208 * Returns an independent copy of the renderer. The <code>plot</code> 1209 * reference is shallow copied. 1210 * 1211 * @return A clone. 1212 * 1213 * @throws CloneNotSupportedException can be thrown if one of the objects 1214 * belonging to the renderer does not support cloning (for example, 1215 * an item label generator). 1216 */ 1217 public Object clone() throws CloneNotSupportedException { 1218 1219 AbstractCategoryItemRenderer clone 1220 = (AbstractCategoryItemRenderer) super.clone(); 1221 1222 if (this.itemLabelGenerator != null) { 1223 if (this.itemLabelGenerator instanceof PublicCloneable) { 1224 PublicCloneable pc = (PublicCloneable) this.itemLabelGenerator; 1225 clone.itemLabelGenerator 1226 = (CategoryItemLabelGenerator) pc.clone(); 1227 } 1228 else { 1229 throw new CloneNotSupportedException( 1230 "ItemLabelGenerator not cloneable." 1231 ); 1232 } 1233 } 1234 1235 if (this.itemLabelGeneratorList != null) { 1236 clone.itemLabelGeneratorList 1237 = (ObjectList) this.itemLabelGeneratorList.clone(); 1238 } 1239 1240 if (this.baseItemLabelGenerator != null) { 1241 if (this.baseItemLabelGenerator instanceof PublicCloneable) { 1242 PublicCloneable pc 1243 = (PublicCloneable) this.baseItemLabelGenerator; 1244 clone.baseItemLabelGenerator 1245 = (CategoryItemLabelGenerator) pc.clone(); 1246 } 1247 else { 1248 throw new CloneNotSupportedException( 1249 "ItemLabelGenerator not cloneable." 1250 ); 1251 } 1252 } 1253 1254 if (this.toolTipGenerator != null) { 1255 if (this.toolTipGenerator instanceof PublicCloneable) { 1256 PublicCloneable pc = (PublicCloneable) this.toolTipGenerator; 1257 clone.toolTipGenerator = (CategoryToolTipGenerator) pc.clone(); 1258 } 1259 else { 1260 throw new CloneNotSupportedException( 1261 "Tool tip generator not cloneable."); 1262 } 1263 } 1264 1265 if (this.toolTipGeneratorList != null) { 1266 clone.toolTipGeneratorList 1267 = (ObjectList) this.toolTipGeneratorList.clone(); 1268 } 1269 1270 if (this.baseToolTipGenerator != null) { 1271 if (this.baseToolTipGenerator instanceof PublicCloneable) { 1272 PublicCloneable pc 1273 = (PublicCloneable) this.baseToolTipGenerator; 1274 clone.baseToolTipGenerator 1275 = (CategoryToolTipGenerator) pc.clone(); 1276 } 1277 else { 1278 throw new CloneNotSupportedException( 1279 "Base tool tip generator not cloneable."); 1280 } 1281 } 1282 1283 if (this.itemURLGenerator != null) { 1284 if (this.itemURLGenerator instanceof PublicCloneable) { 1285 PublicCloneable pc = (PublicCloneable) this.itemURLGenerator; 1286 clone.itemURLGenerator = (CategoryURLGenerator) pc.clone(); 1287 } 1288 else { 1289 throw new CloneNotSupportedException( 1290 "Item URL generator not cloneable."); 1291 } 1292 } 1293 1294 if (this.itemURLGeneratorList != null) { 1295 clone.itemURLGeneratorList 1296 = (ObjectList) this.itemURLGeneratorList.clone(); 1297 } 1298 1299 if (this.baseItemURLGenerator != null) { 1300 if (this.baseItemURLGenerator instanceof PublicCloneable) { 1301 PublicCloneable pc 1302 = (PublicCloneable) this.baseItemURLGenerator; 1303 clone.baseItemURLGenerator = (CategoryURLGenerator) pc.clone(); 1304 } 1305 else { 1306 throw new CloneNotSupportedException( 1307 "Base item URL generator not cloneable."); 1308 } 1309 } 1310 1311 if (this.legendItemLabelGenerator instanceof PublicCloneable) { 1312 clone.legendItemLabelGenerator = (CategorySeriesLabelGenerator) 1313 ObjectUtilities.clone(this.legendItemLabelGenerator); 1314 } 1315 if (this.legendItemToolTipGenerator instanceof PublicCloneable) { 1316 clone.legendItemToolTipGenerator = (CategorySeriesLabelGenerator) 1317 ObjectUtilities.clone(this.legendItemToolTipGenerator); 1318 } 1319 if (this.legendItemURLGenerator instanceof PublicCloneable) { 1320 clone.legendItemURLGenerator = (CategorySeriesLabelGenerator) 1321 ObjectUtilities.clone(this.legendItemURLGenerator); 1322 } 1323 return clone; 1324 } 1325 1326 /** 1327 * Returns a domain axis for a plot. 1328 * 1329 * @param plot the plot. 1330 * @param index the axis index. 1331 * 1332 * @return A domain axis. 1333 */ 1334 protected CategoryAxis getDomainAxis(CategoryPlot plot, int index) { 1335 CategoryAxis result = plot.getDomainAxis(index); 1336 if (result == null) { 1337 result = plot.getDomainAxis(); 1338 } 1339 return result; 1340 } 1341 1342 /** 1343 * Returns a range axis for a plot. 1344 * 1345 * @param plot the plot. 1346 * @param index the axis index. 1347 * 1348 * @return A range axis. 1349 */ 1350 protected ValueAxis getRangeAxis(CategoryPlot plot, int index) { 1351 ValueAxis result = plot.getRangeAxis(index); 1352 if (result == null) { 1353 result = plot.getRangeAxis(); 1354 } 1355 return result; 1356 } 1357 1358 /** 1359 * Returns a (possibly empty) collection of legend items for the series 1360 * that this renderer is responsible for drawing. 1361 * 1362 * @return The legend item collection (never <code>null</code>). 1363 */ 1364 public LegendItemCollection getLegendItems() { 1365 if (this.plot == null) { 1366 return new LegendItemCollection(); 1367 } 1368 LegendItemCollection result = new LegendItemCollection(); 1369 int index = this.plot.getIndexOf(this); 1370 CategoryDataset dataset = this.plot.getDataset(index); 1371 if (dataset != null) { 1372 int seriesCount = dataset.getRowCount(); 1373 for (int i = 0; i < seriesCount; i++) { 1374 if (isSeriesVisibleInLegend(i)) { 1375 LegendItem item = getLegendItem(index, i); 1376 if (item != null) { 1377 result.add(item); 1378 } 1379 } 1380 } 1381 1382 } 1383 return result; 1384 } 1385 1386 /** 1387 * Returns the legend item label generator. 1388 * 1389 * @return The label generator (never <code>null</code>). 1390 * 1391 * @see #setLegendItemLabelGenerator(CategorySeriesLabelGenerator) 1392 */ 1393 public CategorySeriesLabelGenerator getLegendItemLabelGenerator() { 1394 return this.legendItemLabelGenerator; 1395 } 1396 1397 /** 1398 * Sets the legend item label generator and sends a 1399 * {@link RendererChangeEvent} to all registered listeners. 1400 * 1401 * @param generator the generator (<code>null</code> not permitted). 1402 * 1403 * @see #getLegendItemLabelGenerator() 1404 */ 1405 public void setLegendItemLabelGenerator( 1406 CategorySeriesLabelGenerator generator) { 1407 if (generator == null) { 1408 throw new IllegalArgumentException("Null 'generator' argument."); 1409 } 1410 this.legendItemLabelGenerator = generator; 1411 notifyListeners(new RendererChangeEvent(this)); 1412 } 1413 1414 /** 1415 * Returns the legend item tool tip generator. 1416 * 1417 * @return The tool tip generator (possibly <code>null</code>). 1418 * 1419 * @see #setLegendItemToolTipGenerator(CategorySeriesLabelGenerator) 1420 */ 1421 public CategorySeriesLabelGenerator getLegendItemToolTipGenerator() { 1422 return this.legendItemToolTipGenerator; 1423 } 1424 1425 /** 1426 * Sets the legend item tool tip generator and sends a 1427 * {@link RendererChangeEvent} to all registered listeners. 1428 * 1429 * @param generator the generator (<code>null</code> permitted). 1430 * 1431 * @see #setLegendItemToolTipGenerator(CategorySeriesLabelGenerator) 1432 */ 1433 public void setLegendItemToolTipGenerator( 1434 CategorySeriesLabelGenerator generator) { 1435 this.legendItemToolTipGenerator = generator; 1436 notifyListeners(new RendererChangeEvent(this)); 1437 } 1438 1439 /** 1440 * Returns the legend item URL generator. 1441 * 1442 * @return The URL generator (possibly <code>null</code>). 1443 * 1444 * @see #setLegendItemURLGenerator(CategorySeriesLabelGenerator) 1445 */ 1446 public CategorySeriesLabelGenerator getLegendItemURLGenerator() { 1447 return this.legendItemURLGenerator; 1448 } 1449 1450 /** 1451 * Sets the legend item URL generator and sends a 1452 * {@link RendererChangeEvent} to all registered listeners. 1453 * 1454 * @param generator the generator (<code>null</code> permitted). 1455 * 1456 * @see #getLegendItemURLGenerator() 1457 */ 1458 public void setLegendItemURLGenerator( 1459 CategorySeriesLabelGenerator generator) { 1460 this.legendItemURLGenerator = generator; 1461 notifyListeners(new RendererChangeEvent(this)); 1462 } 1463 1464 /** 1465 * Adds an entity with the specified hotspot, but only if an entity 1466 * collection is accessible via the renderer state. 1467 * 1468 * @param entities the entity collection. 1469 * @param dataset the dataset. 1470 * @param row the row index. 1471 * @param column the column index. 1472 * @param hotspot the hotspot. 1473 */ 1474 protected void addItemEntity(EntityCollection entities, 1475 CategoryDataset dataset, int row, int column, 1476 Shape hotspot) { 1477 1478 String tip = null; 1479 CategoryToolTipGenerator tipster = getToolTipGenerator(row, column); 1480 if (tipster != null) { 1481 tip = tipster.generateToolTip(dataset, row, column); 1482 } 1483 String url = null; 1484 CategoryURLGenerator urlster = getItemURLGenerator(row, column); 1485 if (urlster != null) { 1486 url = urlster.generateURL(dataset, row, column); 1487 } 1488 CategoryItemEntity entity = new CategoryItemEntity(hotspot, tip, url, 1489 dataset, row, dataset.getColumnKey(column), column); 1490 entities.add(entity); 1491 1492 } 1493 1494 }