001 /* ====================================================== 002 * Orson : a free chart beans library based on JFreeChart 003 * ====================================================== 004 * 005 * (C) Copyright 2007, by Object Refinery Limited. 006 * 007 * Project Info: not-yet-released 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 029 package org.jfree.beans; 030 031 import java.awt.Font; 032 import java.awt.Insets; 033 import java.awt.Paint; 034 import java.awt.event.MouseEvent; 035 import java.beans.PropertyChangeEvent; 036 import java.text.NumberFormat; 037 038 import org.jfree.beans.events.CategoryItemClickEvent; 039 import org.jfree.beans.events.CategoryItemClickListener; 040 import org.jfree.chart.axis.AxisLocation; 041 import org.jfree.chart.entity.CategoryItemEntity; 042 import org.jfree.chart.entity.ChartEntity; 043 import org.jfree.chart.entity.EntityCollection; 044 import org.jfree.chart.labels.StandardCategoryToolTipGenerator; 045 import org.jfree.chart.plot.CategoryPlot; 046 import org.jfree.chart.plot.PlotOrientation; 047 import org.jfree.chart.renderer.category.CategoryItemRenderer; 048 049 /** 050 * A base class for chart beans that use a {@link CategoryPlot}. 051 */ 052 public abstract class AbstractCategoryChart extends AbstractChart { 053 054 /** 055 * Creates a new instance. 056 */ 057 public AbstractCategoryChart() { 058 super(); 059 } 060 061 /** 062 * Returns the orientation for the plot. 063 * 064 * @return The orientation for the plot. 065 * 066 * @see #setOrientation(PlotOrientation) 067 */ 068 public PlotOrientation getOrientation() { 069 PlotOrientation result = null; 070 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 071 if (plot != null) { 072 result = plot.getOrientation(); 073 } 074 return result; 075 } 076 077 /** 078 * Sets the orientation for the plot and fires a 079 * {@link PropertyChangeEvent} for the <code>orientation</code> property. 080 * 081 * @param orientation the orientation (<code>null</code> not permitted). 082 * 083 * @see #getOrientation() 084 */ 085 public void setOrientation(PlotOrientation orientation) { 086 if (orientation == null) { 087 throw new IllegalArgumentException("Null 'orientation' argument."); 088 } 089 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 090 if (plot != null) { 091 PlotOrientation old = plot.getOrientation(); 092 plot.setOrientation(orientation); 093 firePropertyChange("orientation", old, orientation); 094 } 095 } 096 097 /** 098 * Returns the category axis label. 099 * 100 * @return The category axis label (possibly <code>null</code>). 101 * 102 * @see #setCategoryAxisLabel(String) 103 */ 104 public String getCategoryAxisLabel() { 105 String result = null; 106 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 107 if (plot != null) { 108 result = plot.getDomainAxis().getLabel(); 109 } 110 return result; 111 } 112 113 /** 114 * Sets the category axis label and fires a {@link PropertyChangeEvent} for 115 * the <code>categoryAxisLabel</code> property. 116 * 117 * @param label the label (<code>null</code> permitted). 118 * 119 * @see #getCategoryAxisLabel() 120 */ 121 public void setCategoryAxisLabel(String label) { 122 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 123 if (plot != null) { 124 String old = plot.getDomainAxis().getLabel(); 125 plot.getDomainAxis().setLabel(label); 126 firePropertyChange("categoryAxisLabel", old, label); 127 } 128 } 129 130 /** 131 * Returns the font used for the main label on the category axis. 132 * 133 * @return The font. 134 * 135 * @see #setCategoryAxisLabelFont(Font) 136 */ 137 public Font getCategoryAxisLabelFont() { 138 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 139 if (plot != null) { 140 return plot.getDomainAxis().getLabelFont(); 141 } 142 return null; 143 } 144 145 /** 146 * Sets the font used for the main label on the category axis and fires a 147 * {@link PropertyChangeEvent} for the <code>categoryAxisLabelFont</code> 148 * property. 149 * 150 * @param font the font (<code>null</code> permitted). 151 */ 152 public void setCategoryAxisLabelFont(Font font) { 153 if (font == null) { 154 throw new IllegalArgumentException("Null 'font' argument."); 155 } 156 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 157 if (plot != null) { 158 Font old = plot.getDomainAxis().getLabelFont(); 159 plot.getDomainAxis().setLabelFont(font); 160 firePropertyChange("categoryAxisLabelFont", old, font); 161 } 162 163 } 164 165 /** 166 * Returns the paint used for the main label on the category axis. 167 * 168 * @return The paint. 169 * 170 * @see #setCategoryAxisLabelPaint(Paint) 171 */ 172 public Paint getCategoryAxisLabelPaint() { 173 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 174 if (plot != null) { 175 return plot.getDomainAxis().getLabelPaint(); 176 } 177 return null; 178 } 179 180 /** 181 * Sets the paint used for the main label on the category axis and fires a 182 * {@link PropertyChangeEvent} for the <code>categoryAxisLabelPaint</code> 183 * property. 184 * 185 * @param paint the paint (<code>null</code> not permitted). 186 * 187 * @see #getCategoryAxisLabelPaint() 188 */ 189 public void setCategoryAxisLabelPaint(Paint paint) { 190 if (paint == null) { 191 throw new IllegalArgumentException("Null 'paint' argument."); 192 } 193 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 194 if (plot != null) { 195 Paint old = plot.getDomainAxis().getLabelPaint(); 196 plot.getDomainAxis().setLabelPaint(paint); 197 firePropertyChange("categoryAxisLabelPaint", old, paint); 198 } 199 } 200 201 /** 202 * Returns the lower margin for the category axis. 203 * 204 * @return The lower margin. 205 * 206 * @see #setCategoryAxisLowerMargin(double) 207 */ 208 public double getCategoryAxisLowerMargin() { 209 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 210 if (plot != null) { 211 return plot.getDomainAxis().getLowerMargin(); 212 } 213 return -1.0; 214 } 215 216 /** 217 * Sets the lower margin for the category axis and fires a 218 * {@link PropertyChangeEvent} for the <code>categoryAxisLowerMargin</code> 219 * property. 220 * 221 * @param margin the margin. 222 * 223 * @see #getCategoryAxisLowerMargin() 224 */ 225 public void setCategoryAxisLowerMargin(double margin) { 226 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 227 if (plot != null) { 228 double old = plot.getDomainAxis().getLowerMargin(); 229 plot.getDomainAxis().setLowerMargin(margin); 230 firePropertyChange("categoryAxisLowerMargin", old, margin); 231 } 232 } 233 234 /** 235 * Returns the upper margin for the category axis. 236 * 237 * @return The upper margin for the category axis. 238 * 239 * @see #setCategoryAxisUpperMargin(double) 240 */ 241 public double getCategoryAxisUpperMargin() { 242 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 243 if (plot != null) { 244 return plot.getDomainAxis().getUpperMargin(); 245 } 246 return -1.0; 247 } 248 249 /** 250 * Sets the upper margin for the category axis and fires a 251 * {@link PropertyChangeEvent} for the <code>categoryAxisUpperMargin</code> 252 * property. 253 * 254 * @param margin the margin. 255 * 256 * @see #getCategoryAxisUpperMargin() 257 */ 258 public void setCategoryAxisUpperMargin(double margin) { 259 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 260 if (plot != null) { 261 double old = plot.getDomainAxis().getUpperMargin(); 262 plot.getDomainAxis().setUpperMargin(margin); 263 firePropertyChange("categoryAxisUpperMargin", old, margin); 264 } 265 } 266 267 /** 268 * Returns the margin between categories along the axis. 269 * 270 * @return The margin. 271 * 272 * @see #setCategoryAxisMargin(double) 273 */ 274 public double getCategoryAxisMargin() { 275 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 276 if (plot != null) { 277 return plot.getDomainAxis().getCategoryMargin(); 278 } 279 return -1.0; 280 } 281 282 /** 283 * Sets the total space allocated to the margin between categories 284 * along the axis and fires a {@link PropertyChangeEvent} for 285 * the <code>categoryAxisMargin</code> property. 286 * 287 * @param margin the margin. 288 * 289 * @see #getCategoryAxisMargin() 290 */ 291 public void setCategoryAxisMargin(double margin) { 292 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 293 if (plot != null) { 294 double old = plot.getDomainAxis().getCategoryMargin(); 295 plot.getDomainAxis().setCategoryMargin(margin); 296 firePropertyChange("categoryAxisMargin", old, margin); 297 } 298 } 299 300 /** 301 * Returns the label for the value axis. 302 * 303 * @return The label for the value axis. 304 * 305 * @see #setValueAxisLabel(String) 306 */ 307 public String getValueAxisLabel() { 308 String result = null; 309 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 310 if (plot != null) { 311 result = plot.getRangeAxis().getLabel(); 312 } 313 return result; 314 } 315 316 /** 317 * Sets the label for the value axis and fires a 318 * {@link PropertyChangeEvent} for the <code>valueAxisLabel</code> property. 319 * 320 * @param label the label. 321 * 322 * @see #getValueAxisLabel() 323 */ 324 public void setValueAxisLabel(String label) { 325 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 326 if (plot != null) { 327 String old = plot.getRangeAxis().getLabel(); 328 plot.getRangeAxis().setLabel(label); 329 firePropertyChange("valueAxisLabel", old, label); 330 } 331 } 332 333 /** 334 * Returns <code>true</code> if the value axis is inverted, and 335 * <code>false</code> otherwise. 336 * 337 * @return A boolean. 338 * 339 * @see #setValueAxisInverted(boolean) 340 */ 341 public boolean isValueAxisInverted() { 342 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 343 if (plot != null) { 344 return plot.getRangeAxis().isInverted(); 345 } 346 return false; 347 } 348 349 /** 350 * Sets a flag that controls whether or not the value axis is inverted and 351 * fires a {@link PropertyChangeEvent} for the 352 * <code>valueAxisInverted</code> property. 353 * 354 * @param inverted the new flag value. 355 * 356 * @see #isValueAxisInverted() 357 */ 358 public void setValueAxisInverted(boolean inverted) { 359 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 360 if (plot != null) { 361 boolean old = plot.getRangeAxis().isInverted(); 362 plot.getRangeAxis().setInverted(inverted); 363 firePropertyChange("valueAxisInverted", old, inverted); 364 } 365 } 366 367 /** 368 * Returns the lower margin for the value axis. 369 * 370 * @return The lower margin. 371 * 372 * @see #setValueAxisLowerMargin(double) 373 */ 374 public double getValueAxisLowerMargin() { 375 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 376 if (plot != null) { 377 return plot.getRangeAxis().getLowerMargin(); 378 } 379 return -1.0; 380 } 381 382 /** 383 * Sets the lower margin for the value axis and fires a 384 * {@link PropertyChangeEvent} for the <code>valueAxisLowerMargin</code> 385 * property. 386 * 387 * @param margin the margin. 388 * 389 * @see #getValueAxisLowerMargin() 390 */ 391 public void setValueAxisLowerMargin(double margin) { 392 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 393 if (plot != null) { 394 double old = plot.getRangeAxis().getLowerMargin(); 395 plot.getRangeAxis().setLowerMargin(margin); 396 firePropertyChange("valueAxisLowerMargin", old, margin); 397 } 398 } 399 400 /** 401 * Returns the upper margin for the value axis. 402 * 403 * @return The upper margin for the value axis. 404 * 405 * @see #setValueAxisUpperMargin(double) 406 */ 407 public double getValueAxisUpperMargin() { 408 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 409 if (plot != null) { 410 return plot.getRangeAxis().getUpperMargin(); 411 } 412 return -1.0; 413 } 414 415 /** 416 * Sets the upper margin for the value axis and fires a 417 * {@link PropertyChangeEvent} for the <code>valueAxisUpperMargin</code> 418 * property. 419 * 420 * @param margin the margin. 421 * 422 * @see #getValueAxisUpperMargin() 423 */ 424 public void setValueAxisUpperMargin(double margin) { 425 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 426 if (plot != null) { 427 double old = plot.getRangeAxis().getUpperMargin(); 428 plot.getRangeAxis().setUpperMargin(margin); 429 firePropertyChange("valueAxisUpperMargin", old, margin); 430 } 431 } 432 433 /** 434 * Returns <code>true</code> if the value axis gridlines are visible, and 435 * <code>false</code> otherwise. 436 * 437 * @return A boolean. 438 * 439 * @see #setValueAxisGridlinesVisible(boolean) 440 */ 441 public boolean isValueAxisGridlinesVisible() { 442 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 443 if (plot != null) { 444 return plot.isRangeGridlinesVisible(); 445 } 446 return false; 447 } 448 449 /** 450 * Sets a flag that controls whether or not the value-axis gridlines are 451 * drawn and fires a {@link PropertyChangeEvent} for the 452 * <code>valueAxisGridlinesVisible</code> property. 453 * 454 * @param visible the new flag value. 455 * 456 * @see #isValueAxisGridlinesVisible() 457 */ 458 public void setValueAxisGridlinesVisible(boolean visible) { 459 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 460 if (plot != null) { 461 boolean old = plot.isRangeGridlinesVisible(); 462 plot.setRangeGridlinesVisible(visible); 463 firePropertyChange("valueAxisGridlinesVisible", old, visible); 464 } 465 } 466 467 /** 468 * Returns the flag that controls whether or not the value axis draws a 469 * line running the length of the axis. 470 * 471 * @return A boolean. 472 * 473 * @see #setValueAxisLineVisible(boolean) 474 */ 475 public boolean isValueAxisLineVisible() { 476 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 477 if (plot != null) { 478 return plot.getRangeAxis().isAxisLineVisible(); 479 } 480 return false; 481 } 482 483 /** 484 * Sets the flag that controls whether or not the value axis draws a line 485 * running the length of the axis and fires a {@link PropertyChangeEvent} 486 * for the <code>valueAxisLineVisible</code> property. 487 * 488 * @param visible the new flag value. 489 * 490 * @see #isValueAxisLineVisible() 491 */ 492 public void setValueAxisLineVisible(boolean visible) { 493 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 494 if (plot != null) { 495 boolean old = plot.getRangeAxis().isAxisLineVisible(); 496 plot.getRangeAxis().setAxisLineVisible(visible); 497 firePropertyChange("valueAxisLineVisible", old, visible); 498 } 499 } 500 501 /** 502 * Returns a flag that conrtols whether or not the category axis 503 * draws a line running the length of the axis. 504 * 505 * @return A boolean. 506 * 507 * @see #setCategoryAxisLineVisible(boolean) 508 */ 509 public boolean isCategoryAxisLineVisible() { 510 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 511 if (plot != null) { 512 return plot.getDomainAxis().isAxisLineVisible(); 513 } 514 return false; 515 } 516 517 /** 518 * Sets the flag that controls whether or not the category axis draws a 519 * line running the length of the axis and fires a 520 * {@link PropertyChangeEvent} for the <code>categoryAxisLineVisible</code> 521 * property. 522 * 523 * @param visible the new flag value. 524 * 525 * @see #isCategoryAxisLineVisible() 526 */ 527 public void setCategoryAxisLineVisible(boolean visible) { 528 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 529 if (plot != null) { 530 boolean old = plot.getDomainAxis().isAxisLineVisible(); 531 plot.getDomainAxis().setAxisLineVisible(visible); 532 firePropertyChange("categoryAxisLineVisible", old, visible); 533 } 534 } 535 536 /** 537 * Returns the permitted axis locations for the category axis. 538 * 539 * @return The axis location. 540 * 541 * @see #setCategoryAxisLocation(AxisLocation) 542 */ 543 public AxisLocation getCategoryAxisLocation() { 544 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 545 if (plot != null) { 546 return plot.getDomainAxisLocation(); 547 } 548 return null; 549 } 550 551 /** 552 * Sets the axis location for the category axis and fires a 553 * {@link PropertyChangeEvent} for the <code>categoryAxisLocation</code> 554 * property. 555 * 556 * @param location the location (<code>null</code> not permitted). 557 * 558 * @see #getCategoryAxisLocation() 559 */ 560 public void setCategoryAxisLocation(AxisLocation location) { 561 if (location == null) { 562 throw new IllegalArgumentException("Null 'location' argument."); 563 } 564 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 565 if (plot != null) { 566 AxisLocation old = plot.getDomainAxisLocation(); 567 plot.setDomainAxisLocation(location); 568 firePropertyChange("categoryAxisLocation", old, location); 569 } 570 } 571 572 /** 573 * Returns the permitted axis locations for the value axis. 574 * 575 * @return The axis location. 576 * 577 * @see #setValueAxisLocation(AxisLocation) 578 */ 579 public AxisLocation getValueAxisLocation() { 580 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 581 if (plot != null) { 582 return plot.getRangeAxisLocation(); 583 } 584 return null; 585 } 586 587 /** 588 * Sets the axis location for the value axis and fires a 589 * {@link PropertyChangeEvent} for the <code>valueAxisLocation</code> 590 * property. 591 * 592 * @param location the location (<code>null</code> not permitted). 593 */ 594 public void setValueAxisLocation(AxisLocation location) { 595 if (location == null) { 596 throw new IllegalArgumentException("Null 'location' argument."); 597 } 598 CategoryPlot plot = (CategoryPlot) this.chart.getPlot(); 599 if (plot != null) { 600 AxisLocation old = plot.getRangeAxisLocation(); 601 plot.setRangeAxisLocation(location); 602 firePropertyChange("valueAxisLocation", old, location); 603 } 604 } 605 606 /** 607 * Returns the format string for the item tool tips. 608 * 609 * @return The format string. 610 * 611 * @see #setToolTipFormat(String) 612 */ 613 public String getToolTipFormat() { 614 CategoryPlot p = (CategoryPlot) this.chart.getPlot(); 615 if (p == null) { 616 return ""; 617 } 618 CategoryItemRenderer r = p.getRenderer(); 619 if (r == null) { 620 return ""; 621 } 622 StandardCategoryToolTipGenerator g = (StandardCategoryToolTipGenerator) 623 r.getBaseToolTipGenerator(); 624 if (g == null) { 625 return ""; 626 } 627 return g.getLabelFormat(); 628 } 629 630 /** 631 * Sets the format string for the section tool tips and fires a 632 * {@link PropertyChangeEvent} for the <code>toolTipFormat</code> property. 633 * 634 * @param format the format string. 635 * 636 * @see #getToolTipFormat() 637 */ 638 public void setToolTipFormat(String format) { 639 CategoryPlot p = (CategoryPlot) this.chart.getPlot(); 640 if (p == null) { 641 return; 642 } 643 CategoryItemRenderer r = p.getRenderer(); 644 if (r == null) { 645 return; 646 } 647 if (format.equals("")) { 648 r.setBaseToolTipGenerator(null); 649 } 650 else { 651 r.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator( 652 format, NumberFormat.getInstance())); 653 } 654 // FIXME: what to use for the oldValue 655 firePropertyChange("toolTipFormat", null, format); 656 } 657 658 /** 659 * Registers a listener to receive notification of category item clicks. 660 * 661 * @param listener the listener (<code>null</code> not permitted). 662 */ 663 public void addCategoryItemClickListener( 664 CategoryItemClickListener listener) { 665 if (listener == null) { 666 throw new IllegalArgumentException("Null 'listener' argument."); 667 } 668 this.listeners.add(CategoryItemClickListener.class, listener); 669 } 670 671 /** 672 * Unregisters a listener so that it no longer receives notification of 673 * category item clicks. 674 * 675 * @param listener the listener (<code>null</code> not permitted). 676 */ 677 public void removeCategoryItemClickListener(CategoryItemClickListener 678 listener) { 679 if (listener == null) { 680 throw new IllegalArgumentException("Null 'listener' argument."); 681 } 682 this.listeners.remove(CategoryItemClickListener.class, listener); 683 } 684 685 /** 686 * Fires a category item click event. 687 * 688 * @param event the event. 689 */ 690 public void fireCategoryItemClickEvent(CategoryItemClickEvent event) { 691 Object[] listeners = this.listeners.getListeners( 692 CategoryItemClickListener.class); 693 for (int i = listeners.length - 1; i >= 0; i -= 1) { 694 ((CategoryItemClickListener) listeners[i]).onCategoryItemClick( 695 event); 696 } 697 698 } 699 700 /** 701 * If the user clicks on the chart, see if that translates into an event 702 * that we report... 703 * 704 * @param event the event. 705 */ 706 public void mouseClicked(MouseEvent event) { 707 // if no-one is listening, just return... 708 Object[] listeners = this.listeners.getListeners( 709 CategoryItemClickListener.class); 710 if (listeners.length == 0) { 711 super.mouseClicked(event); 712 } 713 714 Insets insets = getInsets(); 715 int x = event.getX() - insets.left; 716 int y = event.getY() - insets.top; 717 718 ChartEntity entity = null; 719 if (this.info != null) { 720 EntityCollection entities = this.info.getEntityCollection(); 721 if (entities != null) { 722 entity = entities.getEntity(x, y); 723 } 724 } 725 if (entity instanceof CategoryItemEntity) { 726 CategoryItemEntity cie = (CategoryItemEntity) entity; 727 CategoryItemClickEvent lce = new CategoryItemClickEvent(this, 728 cie.getDataset(), cie.getRowKey(), cie.getColumnKey()); 729 fireCategoryItemClickEvent(lce); 730 } 731 else { 732 super.mouseClicked(event); 733 } 734 735 } 736 737 }