JFreeChart

Overview Package Class Use Source Tree Index Deprecated About

Frames | No Frames

Source for org.jfree.chart.JFreeChart



   1: /* ===========================================================

   2:  * JFreeChart : a free chart library for the Java(tm) platform

   3:  * ===========================================================

   4:  *

   5:  * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.

   6:  *

   7:  * Project Info:  http://www.jfree.org/jfreechart/index.html

   8:  *

   9:  * This library is free software; you can redistribute it and/or modify it 

  10:  * under the terms of the GNU Lesser General Public License as published by 

  11:  * the Free Software Foundation; either version 2.1 of the License, or 

  12:  * (at your option) any later version.

  13:  *

  14:  * This library is distributed in the hope that it will be useful, but 

  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 

  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 

  17:  * License for more details.

  18:  *

  19:  * You should have received a copy of the GNU Lesser General Public

  20:  * License along with this library; if not, write to the Free Software

  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 

  22:  * USA.  

  23:  *

  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 

  25:  * in the United States and other countries.]

  26:  * 

  27:  * ---------------

  28:  * JFreeChart.java

  29:  * ---------------

  30:  * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.

  31:  *

  32:  * Original Author:  David Gilbert (for Object Refinery Limited);

  33:  * Contributor(s):   Andrzej Porebski;

  34:  *                   David Li;

  35:  *                   Wolfgang Irler;

  36:  *                   Christian W. Zuckschwerdt;

  37:  *                   Klaus Rheinwald;

  38:  *                   Nicolas Brodu;

  39:  *                   

  40:  * NOTE: The above list of contributors lists only the people that have

  41:  * contributed to this source file (JFreeChart.java) - for a list of ALL

  42:  * contributors to the project, please see the README.txt file.

  43:  *

  44:  * $Id: JFreeChart.java,v 1.34.2.17 2007/03/22 10:53:54 mungady Exp $

  45:  *

  46:  * Changes (from 20-Jun-2001)

  47:  * --------------------------

  48:  * 20-Jun-2001 : Modifications submitted by Andrzej Porebski for legend 

  49:  *               placement;

  50:  * 21-Jun-2001 : Removed JFreeChart parameter from Plot constructors (DG);

  51:  * 22-Jun-2001 : Multiple titles added (original code by David Berry, with 

  52:  *               reworkings by DG);

  53:  * 18-Sep-2001 : Updated header (DG);

  54:  * 15-Oct-2001 : Moved data source classes into new package 

  55:  *               com.jrefinery.data.* (DG);

  56:  * 18-Oct-2001 : New factory method for creating VerticalXYBarChart (DG);

  57:  * 19-Oct-2001 : Moved series paint and stroke methods to the Plot class (DG);

  58:  *               Moved static chart creation methods to new ChartFactory 

  59:  *               class (DG);

  60:  * 22-Oct-2001 : Renamed DataSource.java --> Dataset.java etc. (DG);

  61:  *               Fixed bug where chart isn't registered with the dataset (DG);

  62:  * 07-Nov-2001 : Fixed bug where null title in constructor causes 

  63:  *               exception (DG);

  64:  *               Tidied up event notification code (DG);

  65:  * 17-Nov-2001 : Added getLegendItemCount() method (DG);

  66:  * 21-Nov-2001 : Set clipping in draw method to ensure that nothing gets drawn 

  67:  *               outside the chart area (DG);

  68:  * 11-Dec-2001 : Added the createBufferedImage() method, taken from the 

  69:  *               JFreeChartServletDemo class (DG);

  70:  * 13-Dec-2001 : Added tooltips (DG);

  71:  * 16-Jan-2002 : Added handleClick() method (DG);

  72:  * 22-Jan-2002 : Fixed bug correlating legend labels with pie data (DG);

  73:  * 05-Feb-2002 : Removed redundant tooltips code (DG);

  74:  * 19-Feb-2002 : Added accessor methods for the backgroundImage and 

  75:  *               backgroundImageAlpha attributes (DG);

  76:  * 21-Feb-2002 : Added static fields for INFO, COPYRIGHT, LICENCE, CONTRIBUTORS

  77:  *               and LIBRARIES.  These can be used to display information about

  78:  *               JFreeChart (DG);

  79:  * 06-Mar-2002 : Moved constants to JFreeChartConstants interface (DG);

  80:  * 18-Apr-2002 : PieDataset is no longer sorted (oldman);

  81:  * 23-Apr-2002 : Moved dataset to the Plot class (DG);

  82:  * 13-Jun-2002 : Added an extra draw() method (DG);

  83:  * 25-Jun-2002 : Implemented the Drawable interface and removed redundant 

  84:  *               imports (DG);

  85:  * 26-Jun-2002 : Added another createBufferedImage() method (DG);

  86:  * 18-Sep-2002 : Fixed issues reported by Checkstyle (DG);

  87:  * 23-Sep-2002 : Added new contributor (DG);

  88:  * 28-Oct-2002 : Created main title and subtitle list to replace existing title

  89:  *               list (DG);

  90:  * 08-Jan-2003 : Added contributor (DG);

  91:  * 17-Jan-2003 : Added new constructor (DG);

  92:  * 22-Jan-2003 : Added ChartColor class by Cameron Riley, and background image 

  93:  *               alignment code by Christian W. Zuckschwerdt (DG);

  94:  * 11-Feb-2003 : Added flag to allow suppression of chart change events, based 

  95:  *               on a suggestion by Klaus Rheinwald (DG);

  96:  * 04-Mar-2003 : Added small fix for suppressed chart change events (see bug id

  97:  *               690865) (DG);

  98:  * 10-Mar-2003 : Added Benoit Xhenseval to contributors (DG);

  99:  * 26-Mar-2003 : Implemented Serializable (DG);

 100:  * 15-Jul-2003 : Added an optional border for the chart (DG);

 101:  * 11-Sep-2003 : Took care of listeners while cloning (NB);

 102:  * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);

 103:  * 22-Sep-2003 : Added nullpointer checks.

 104:  * 25-Sep-2003 : Added nullpointer checks too (NB).

 105:  * 03-Dec-2003 : Legends are now registered by this class instead of using the 

 106:  *               old constructor way (TM);

 107:  * 03-Dec-2003 : Added anchorPoint to draw() method (DG);

 108:  * 08-Jan-2004 : Reworked title code, introducing line wrapping (DG);

 109:  * 09-Feb-2004 : Created additional createBufferedImage() method (DG);

 110:  * 05-Apr-2004 : Added new createBufferedImage() method (DG);

 111:  * 27-May-2004 : Moved constants from JFreeChartConstants.java back to this 

 112:  *               class (DG);

 113:  * 25-Nov-2004 : Updates for changes to Title class (DG);

 114:  * 06-Jan-2005 : Change lookup for default background color (DG);

 115:  * 31-Jan-2005 : Added Don Elliott to contributors (DG);

 116:  * 02-Feb-2005 : Added clearSubtitles() method (DG);

 117:  * 03-Feb-2005 : Added Mofeed Shahin to contributors (DG);

 118:  * 08-Feb-2005 : Updated for RectangleConstraint changes (DG);

 119:  * 28-Mar-2005 : Renamed Legend --> OldLegend (DG);

 120:  * 12-Apr-2005 : Added methods to access legend(s) in subtitle list (DG);

 121:  * 13-Apr-2005 : Added removeLegend() and removeSubtitle() methods (DG);

 122:  * 20-Apr-2005 : Modified to collect chart entities from titles and 

 123:  *               subtitles (DG);

 124:  * 26-Apr-2005 : Removed LOGGER (DG);

 125:  * 06-Jun-2005 : Added addLegend() method and padding attribute, fixed equals() 

 126:  *               method (DG);

 127:  * 24-Nov-2005 : Removed OldLegend and related code - don't want to support

 128:  *               this in 1.0.0 final (DG);

 129:  * ------------- JFREECHART 1.0.x ---------------------------------------------

 130:  * 27-Jan-2006 : Updated version number (DG);

 131:  * 07-Dec-2006 : Added some missing credits (DG);

 132:  * 17-Jan-2007 : Added Darren Jung to contributor list (DG);

 133:  * 05-Mar-2007 : Added Sergei Ivanov to the contributor list (DG);

 134:  * 16-Mar-2007 : Modified initial legend border (DG);

 135:  * 22-Mar-2007 : New methods for text anti-aliasing (DG);

 136:  * 

 137:  */

 138: 

 139: package org.jfree.chart;

 140: 

 141: import java.awt.AlphaComposite;

 142: import java.awt.BasicStroke;

 143: import java.awt.Color;

 144: import java.awt.Composite;

 145: import java.awt.Font;

 146: import java.awt.Graphics2D;

 147: import java.awt.Image;

 148: import java.awt.Paint;

 149: import java.awt.RenderingHints;

 150: import java.awt.Shape;

 151: import java.awt.Stroke;

 152: import java.awt.geom.AffineTransform;

 153: import java.awt.geom.Point2D;

 154: import java.awt.geom.Rectangle2D;

 155: import java.awt.image.BufferedImage;

 156: import java.io.IOException;

 157: import java.io.ObjectInputStream;

 158: import java.io.ObjectOutputStream;

 159: import java.io.Serializable;

 160: import java.net.URL;

 161: import java.util.ArrayList;

 162: import java.util.Arrays;

 163: import java.util.Iterator;

 164: import java.util.List;

 165: import java.util.ResourceBundle;

 166: 

 167: import javax.swing.ImageIcon;

 168: import javax.swing.UIManager;

 169: import javax.swing.event.EventListenerList;

 170: 

 171: import org.jfree.JCommon;

 172: import org.jfree.chart.block.BlockParams;

 173: import org.jfree.chart.block.EntityBlockResult;

 174: import org.jfree.chart.block.LengthConstraintType;

 175: import org.jfree.chart.block.LineBorder;

 176: import org.jfree.chart.block.RectangleConstraint;

 177: import org.jfree.chart.entity.EntityCollection;

 178: import org.jfree.chart.event.ChartChangeEvent;

 179: import org.jfree.chart.event.ChartChangeListener;

 180: import org.jfree.chart.event.ChartProgressEvent;

 181: import org.jfree.chart.event.ChartProgressListener;

 182: import org.jfree.chart.event.PlotChangeEvent;

 183: import org.jfree.chart.event.PlotChangeListener;

 184: import org.jfree.chart.event.TitleChangeEvent;

 185: import org.jfree.chart.event.TitleChangeListener;

 186: import org.jfree.chart.plot.CategoryPlot;

 187: import org.jfree.chart.plot.Plot;

 188: import org.jfree.chart.plot.PlotRenderingInfo;

 189: import org.jfree.chart.plot.XYPlot;

 190: import org.jfree.chart.title.LegendTitle;

 191: import org.jfree.chart.title.TextTitle;

 192: import org.jfree.chart.title.Title;

 193: import org.jfree.data.Range;

 194: import org.jfree.io.SerialUtilities;

 195: import org.jfree.ui.Align;

 196: import org.jfree.ui.Drawable;

 197: import org.jfree.ui.HorizontalAlignment;

 198: import org.jfree.ui.RectangleEdge;

 199: import org.jfree.ui.RectangleInsets;

 200: import org.jfree.ui.Size2D;

 201: import org.jfree.ui.VerticalAlignment;

 202: import org.jfree.ui.about.Contributor;

 203: import org.jfree.ui.about.Licences;

 204: import org.jfree.ui.about.ProjectInfo;

 205: import org.jfree.util.ObjectUtilities;

 206: import org.jfree.util.PaintUtilities;

 207: 

 208: /**

 209:  * A chart class implemented using the Java 2D APIs.  The current version

 210:  * supports bar charts, line charts, pie charts and xy plots (including time

 211:  * series data).

 212:  * <P>

 213:  * JFreeChart coordinates several objects to achieve its aim of being able to

 214:  * draw a chart on a Java 2D graphics device: a list of {@link Title} objects

 215:  * (which often includes the chart's legend), a {@link Plot} and a 

 216:  * {@link org.jfree.data.general.Dataset} (the plot in turn manages a 

 217:  * domain axis and a range axis).

 218:  * <P>

 219:  * You should use a {@link ChartPanel} to display a chart in a GUI.

 220:  * <P>

 221:  * The {@link ChartFactory} class contains static methods for creating 

 222:  * 'ready-made' charts.

 223:  *

 224:  * @see ChartPanel

 225:  * @see ChartFactory

 226:  * @see Title

 227:  * @see Plot

 228:  */

 229: public class JFreeChart implements Drawable,

 230:                                    TitleChangeListener,

 231:                                    PlotChangeListener,

 232:                                    Serializable,

 233:                                    Cloneable {

 234: 

 235:     /** For serialization. */    

 236:     private static final long serialVersionUID = -3470703747817429120L;

 237:     

 238:     /** Information about the project. */

 239:     public static final ProjectInfo INFO = new JFreeChartInfo();

 240: 

 241:     /** The default font for titles. */

 242:     public static final Font DEFAULT_TITLE_FONT 

 243:             = new Font("SansSerif", Font.BOLD, 18);

 244: 

 245:     /** The default background color. */

 246:     public static final Paint DEFAULT_BACKGROUND_PAINT 

 247:             = UIManager.getColor("Panel.background");

 248: 

 249:     /** The default background image. */

 250:     public static final Image DEFAULT_BACKGROUND_IMAGE = null;

 251: 

 252:     /** The default background image alignment. */

 253:     public static final int DEFAULT_BACKGROUND_IMAGE_ALIGNMENT = Align.FIT;

 254: 

 255:     /** The default background image alpha. */

 256:     public static final float DEFAULT_BACKGROUND_IMAGE_ALPHA = 0.5f;

 257: 

 258:     /** 

 259:      * Rendering hints that will be used for chart drawing.  This should never

 260:      * be <code>null</code>. 

 261:      */

 262:     private transient RenderingHints renderingHints;

 263: 

 264:     /** A flag that controls whether or not the chart border is drawn. */

 265:     private boolean borderVisible;

 266: 

 267:     /** The stroke used to draw the chart border (if visible). */

 268:     private transient Stroke borderStroke;

 269: 

 270:     /** The paint used to draw the chart border (if visible). */

 271:     private transient Paint borderPaint;

 272: 

 273:     /** The padding between the chart border and the chart drawing area. */

 274:     private RectangleInsets padding;

 275:     

 276:     /** The chart title (optional). */

 277:     private TextTitle title;

 278: 

 279:     /** The chart subtitles (zero, one or many). */

 280:     private List subtitles;

 281: 

 282:     /** Draws the visual representation of the data. */

 283:     private Plot plot;

 284: 

 285:     /** Paint used to draw the background of the chart. */

 286:     private transient Paint backgroundPaint;

 287: 

 288:     /** An optional background image for the chart. */

 289:     private transient Image backgroundImage;  // todo: not serialized yet

 290: 

 291:     /** The alignment for the background image. */

 292:     private int backgroundImageAlignment = Align.FIT;

 293: 

 294:     /** The alpha transparency for the background image. */

 295:     private float backgroundImageAlpha = 0.5f;

 296: 

 297:     /** Storage for registered change listeners. */

 298:     private transient EventListenerList changeListeners;

 299: 

 300:     /** Storage for registered progress listeners. */

 301:     private transient EventListenerList progressListeners;

 302: 

 303:     /** 

 304:      * A flag that can be used to enable/disable notification of chart change 

 305:      * events. 

 306:      */

 307:     private boolean notify;

 308:     

 309:     /**

 310:      * Creates a new chart based on the supplied plot.  The chart will have

 311:      * a legend added automatically, but no title (although you can easily add

 312:      * one later).  

 313:      * <br><br>

 314:      * Note that the  {@link ChartFactory} class contains a range 

 315:      * of static methods that will return ready-made charts, and often this

 316:      * is a more convenient way to create charts than using this constructor.

 317:      *

 318:      * @param plot  the plot (<code>null</code> not permitted).

 319:      */

 320:     public JFreeChart(Plot plot) {

 321:         this(null, null, plot, true);

 322:     }

 323: 

 324:     /**

 325:      * Creates a new chart with the given title and plot.  A default font 

 326:      * (@link DEFAULT_TITLE_FONT) is used for the title, and the chart will 

 327:      * have a legend added automatically.  

 328:      * <br><br>

 329:      * Note that the  {@link ChartFactory} class contains a range 

 330:      * of static methods that will return ready-made charts, and often this

 331:      * is a more convenient way to create charts than using this constructor.

 332:      *

 333:      * @param title  the chart title (<code>null</code> permitted).

 334:      * @param plot  the plot (<code>null</code> not permitted).

 335:      */

 336:     public JFreeChart(String title, Plot plot) {

 337:         this(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);

 338:     }

 339: 

 340:     /**

 341:      * Creates a new chart with the given title and plot.  The 

 342:      * <code>createLegend</code> argument specifies whether or not a legend

 343:      * should be added to the chart.  

 344:      * <br><br>

 345:      * Note that the  {@link ChartFactory} class contains a range 

 346:      * of static methods that will return ready-made charts, and often this

 347:      * is a more convenient way to create charts than using this constructor.

 348:      *

 349:      * @param title  the chart title (<code>null</code> permitted).

 350:      * @param titleFont  the font for displaying the chart title 

 351:      *                   (<code>null</code> permitted).

 352:      * @param plot  controller of the visual representation of the data 

 353:      *              (<code>null</code> not permitted).

 354:      * @param createLegend  a flag indicating whether or not a legend should   

 355:      *                      be created for the chart.

 356:      */

 357:     public JFreeChart(String title, Font titleFont, Plot plot, 

 358:                       boolean createLegend) {

 359: 

 360:         if (plot == null) {

 361:             throw new NullPointerException("Null 'plot' argument.");

 362:         }

 363: 

 364:         // create storage for listeners...

 365:         this.progressListeners = new EventListenerList();

 366:         this.changeListeners = new EventListenerList();

 367:         this.notify = true;  // default is to notify listeners when the 

 368:                              // chart changes

 369: 

 370:         this.renderingHints = new RenderingHints(

 371:                 RenderingHints.KEY_ANTIALIASING, 

 372:                 RenderingHints.VALUE_ANTIALIAS_ON);

 373: 

 374:         this.borderVisible = false;

 375:         this.borderStroke = new BasicStroke(1.0f);

 376:         this.borderPaint = Color.black;

 377: 

 378:         this.padding = RectangleInsets.ZERO_INSETS;

 379:         

 380:         this.plot = plot;

 381:         plot.addChangeListener(this);

 382: 

 383:         this.subtitles = new ArrayList();

 384: 

 385:         // create a legend, if requested...

 386:         if (createLegend) {

 387:             LegendTitle legend = new LegendTitle(this.plot);

 388:             legend.setMargin(new RectangleInsets(1.0, 1.0, 1.0, 1.0));

 389:             legend.setFrame(new LineBorder());

 390:             legend.setBackgroundPaint(Color.white);

 391:             legend.setPosition(RectangleEdge.BOTTOM);

 392:             this.subtitles.add(legend);

 393:         }

 394: 

 395:         // add the chart title, if one has been specified...

 396:         if (title != null) {

 397:             if (titleFont == null) {

 398:                 titleFont = DEFAULT_TITLE_FONT;

 399:             }

 400:             this.title = new TextTitle(title, titleFont);

 401:             this.title.addChangeListener(this);

 402:         }

 403: 

 404:         this.backgroundPaint = DEFAULT_BACKGROUND_PAINT;

 405: 

 406:         this.backgroundImage = DEFAULT_BACKGROUND_IMAGE;

 407:         this.backgroundImageAlignment = DEFAULT_BACKGROUND_IMAGE_ALIGNMENT;

 408:         this.backgroundImageAlpha = DEFAULT_BACKGROUND_IMAGE_ALPHA;

 409: 

 410:     }

 411: 

 412:     /**

 413:      * Returns the collection of rendering hints for the chart.

 414:      *

 415:      * @return The rendering hints for the chart (never <code>null</code>).

 416:      * 

 417:      * @see #setRenderingHints(RenderingHints)

 418:      */

 419:     public RenderingHints getRenderingHints() {

 420:         return this.renderingHints;

 421:     }

 422: 

 423:     /**

 424:      * Sets the rendering hints for the chart.  These will be added (using the 

 425:      * Graphics2D.addRenderingHints() method) near the start of the 

 426:      * JFreeChart.draw() method.

 427:      *

 428:      * @param renderingHints  the rendering hints (<code>null</code> not 

 429:      *                        permitted).

 430:      *                        

 431:      * @see #getRenderingHints()

 432:      */

 433:     public void setRenderingHints(RenderingHints renderingHints) {

 434:         if (renderingHints == null) {

 435:             throw new NullPointerException("RenderingHints given are null");

 436:         }

 437:         this.renderingHints = renderingHints;

 438:         fireChartChanged();

 439:     }

 440: 

 441:     /**

 442:      * Returns a flag that controls whether or not a border is drawn around the

 443:      * outside of the chart.

 444:      *

 445:      * @return A boolean.

 446:      * 

 447:      * @see #setBorderVisible(boolean)

 448:      */

 449:     public boolean isBorderVisible() {

 450:         return this.borderVisible;

 451:     }

 452: 

 453:     /**

 454:      * Sets a flag that controls whether or not a border is drawn around the 

 455:      * outside of the chart.

 456:      *

 457:      * @param visible  the flag.

 458:      * 

 459:      * @see #isBorderVisible()

 460:      */

 461:     public void setBorderVisible(boolean visible) {

 462:         this.borderVisible = visible;

 463:         fireChartChanged();

 464:     }

 465: 

 466:     /**

 467:      * Returns the stroke used to draw the chart border (if visible).

 468:      *

 469:      * @return The border stroke.

 470:      * 

 471:      * @see #setBorderStroke(Stroke)

 472:      */

 473:     public Stroke getBorderStroke() {

 474:         return this.borderStroke;

 475:     }

 476: 

 477:     /**

 478:      * Sets the stroke used to draw the chart border (if visible).

 479:      *

 480:      * @param stroke  the stroke.

 481:      * 

 482:      * @see #getBorderStroke()

 483:      */

 484:     public void setBorderStroke(Stroke stroke) {

 485:         this.borderStroke = stroke;

 486:         fireChartChanged();

 487:     }

 488: 

 489:     /**

 490:      * Returns the paint used to draw the chart border (if visible).

 491:      *

 492:      * @return The border paint.

 493:      * 

 494:      * @see #setBorderPaint(Paint)

 495:      */

 496:     public Paint getBorderPaint() {

 497:         return this.borderPaint;

 498:     }

 499: 

 500:     /**

 501:      * Sets the paint used to draw the chart border (if visible).

 502:      *

 503:      * @param paint  the paint.

 504:      * 

 505:      * @see #getBorderPaint()

 506:      */

 507:     public void setBorderPaint(Paint paint) {

 508:         this.borderPaint = paint;

 509:         fireChartChanged();

 510:     }

 511:     

 512:     /**

 513:      * Returns the padding between the chart border and the chart drawing area.

 514:      * 

 515:      * @return The padding (never <code>null</code>).

 516:      * 

 517:      * @see #setPadding(RectangleInsets)

 518:      */

 519:     public RectangleInsets getPadding() {

 520:         return this.padding;   

 521:     }

 522: 

 523:     /**

 524:      * Sets the padding between the chart border and the chart drawing area,

 525:      * and sends a {@link ChartChangeEvent} to all registered listeners.

 526:      * 

 527:      * @param padding  the padding (<code>null</code> not permitted).

 528:      * 

 529:      * @see #getPadding()

 530:      */

 531:     public void setPadding(RectangleInsets padding) {

 532:         if (padding == null) {

 533:             throw new IllegalArgumentException("Null 'padding' argument.");   

 534:         }

 535:         this.padding = padding;

 536:         notifyListeners(new ChartChangeEvent(this));

 537:     }

 538:     

 539:     /**

 540:      * Returns the main chart title.  Very often a chart will have just one

 541:      * title, so we make this case simple by providing accessor methods for

 542:      * the main title.  However, multiple titles are supported - see the

 543:      * {@link #addSubtitle(Title)} method.

 544:      *

 545:      * @return The chart title (possibly <code>null</code>).

 546:      * 

 547:      * @see #setTitle(TextTitle)

 548:      */

 549:     public TextTitle getTitle() {

 550:         return this.title;

 551:     }

 552: 

 553:     /**

 554:      * Sets the main title for the chart and sends a {@link ChartChangeEvent} 

 555:      * to all registered listeners.  If you do not want a title for the 

 556:      * chart, set it to <code>null</code>.  If you want more than one title on

 557:      * a chart, use the {@link #addSubtitle(Title)} method.

 558:      *

 559:      * @param title  the title (<code>null</code> permitted).

 560:      * 

 561:      * @see #getTitle()

 562:      */

 563:     public void setTitle(TextTitle title) {

 564:         this.title = title;

 565:         fireChartChanged();

 566:     }

 567: 

 568:     /**

 569:      * Sets the chart title and sends a {@link ChartChangeEvent} to all 

 570:      * registered listeners.  This is a convenience method that ends up calling 

 571:      * the {@link #setTitle(TextTitle)} method.  If there is an existing title,

 572:      * its text is updated, otherwise a new title using the default font is 

 573:      * added to the chart.  If <code>text</code> is <code>null</code> the chart

 574:      * title is set to <code>null</code>.

 575:      *

 576:      * @param text  the title text (<code>null</code> permitted).

 577:      * 

 578:      * @see #getTitle()

 579:      */

 580:     public void setTitle(String text) {

 581:         if (text != null) {

 582:             if (this.title == null) {

 583:                 setTitle(new TextTitle(text, JFreeChart.DEFAULT_TITLE_FONT));

 584:             }

 585:             else {

 586:                 this.title.setText(text);

 587:             }

 588:         }

 589:         else {

 590:             setTitle((TextTitle) null);

 591:         }

 592:     }

 593: 

 594:     /**

 595:      * Adds a legend to the plot and sends a {@link ChartChangeEvent} to all

 596:      * registered listeners.

 597:      * 

 598:      * @param legend  the legend (<code>null</code> not permitted).

 599:      * 

 600:      * @see #removeLegend()

 601:      */

 602:     public void addLegend(LegendTitle legend) {

 603:         addSubtitle(legend);    

 604:     }

 605:     

 606:     /**

 607:      * Returns the legend for the chart, if there is one.  Note that a chart

 608:      * can have more than one legend - this method returns the first.

 609:      * 

 610:      * @return The legend (possibly <code>null</code>).

 611:      * 

 612:      * @see #getLegend(int)

 613:      */

 614:     public LegendTitle getLegend() {

 615:         return getLegend(0);

 616:     }

 617:     

 618:     /**

 619:      * Returns the nth legend for a chart, or <code>null</code>.

 620:      * 

 621:      * @param index  the legend index (zero-based).

 622:      * 

 623:      * @return The legend (possibly <code>null</code>).

 624:      * 

 625:      * @see #addLegend(LegendTitle)

 626:      */

 627:     public LegendTitle getLegend(int index) {

 628:         int seen = 0;

 629:         Iterator iterator = this.subtitles.iterator();

 630:         while (iterator.hasNext()) {

 631:             Title subtitle = (Title) iterator.next();

 632:             if (subtitle instanceof LegendTitle) {

 633:                 if (seen == index) {

 634:                     return (LegendTitle) subtitle;

 635:                 }

 636:                 else {

 637:                     seen++;   

 638:                 }

 639:             }

 640:         }

 641:         return null;        

 642:     }

 643:     

 644:     /**

 645:      * Removes the first legend in the chart and sends a 

 646:      * {@link ChartChangeEvent} to all registered listeners.

 647:      * 

 648:      * @see #getLegend()

 649:      */

 650:     public void removeLegend() {

 651:         removeSubtitle(getLegend());

 652:     }

 653:     

 654:     /**

 655:      * Returns the list of subtitles for the chart.

 656:      *

 657:      * @return The subtitle list (possibly empty, but never <code>null</code>).

 658:      * 

 659:      * @see #setSubtitles(List)

 660:      */

 661:     public List getSubtitles() {

 662:         return this.subtitles;

 663:     }

 664: 

 665:     /**

 666:      * Sets the title list for the chart (completely replaces any existing 

 667:      * titles).

 668:      *

 669:      * @param subtitles  the new list of subtitles (<code>null</code> not 

 670:      *                   permitted).

 671:      *                   

 672:      * @see #getSubtitles()

 673:      */

 674:     public void setSubtitles(List subtitles) {

 675:         if (subtitles == null) {

 676:             throw new NullPointerException("Null 'subtitles' argument.");

 677:         }

 678:         this.subtitles = subtitles;

 679:         fireChartChanged();

 680:     }

 681: 

 682:     /**

 683:      * Returns the number of titles for the chart.

 684:      *

 685:      * @return The number of titles for the chart.

 686:      * 

 687:      * @see #getSubtitles()

 688:      */

 689:     public int getSubtitleCount() {

 690:         return this.subtitles.size();

 691:     }

 692: 

 693:     /**

 694:      * Returns a chart subtitle.

 695:      *

 696:      * @param index  the index of the chart subtitle (zero based).

 697:      *

 698:      * @return A chart subtitle.

 699:      * 

 700:      * @see #addSubtitle(Title)

 701:      */

 702:     public Title getSubtitle(int index) {

 703:         if ((index < 0) || (index == getSubtitleCount())) {

 704:             throw new IllegalArgumentException("Index out of range.");

 705:         }

 706:         return (Title) this.subtitles.get(index);

 707:     }

 708: 

 709:     /**

 710:      * Adds a chart subtitle, and notifies registered listeners that the chart 

 711:      * has been modified.

 712:      *

 713:      * @param subtitle  the subtitle (<code>null</code> not permitted).

 714:      * 

 715:      * @see #getSubtitle(int)

 716:      */

 717:     public void addSubtitle(Title subtitle) {

 718:         if (subtitle == null) {

 719:             throw new IllegalArgumentException("Null 'subtitle' argument.");

 720:         }

 721:         this.subtitles.add(subtitle);

 722:         subtitle.addChangeListener(this);

 723:         fireChartChanged();

 724:     }

 725:     

 726:     /**

 727:      * Clears all subtitles from the chart and sends a {@link ChartChangeEvent}

 728:      * to all registered listeners.

 729:      * 

 730:      * @see #addSubtitle(Title)

 731:      */

 732:     public void clearSubtitles() {

 733:         Iterator iterator = this.subtitles.iterator();

 734:         while (iterator.hasNext()) {

 735:             Title t = (Title) iterator.next();

 736:             t.removeChangeListener(this);

 737:         }

 738:         this.subtitles.clear();

 739:         fireChartChanged();

 740:     }

 741: 

 742:     /**

 743:      * Removes the specified subtitle and sends a {@link ChartChangeEvent} to

 744:      * all registered listeners.

 745:      * 

 746:      * @param title  the title.

 747:      * 

 748:      * @see #addSubtitle(Title)

 749:      */

 750:     public void removeSubtitle(Title title) {

 751:         this.subtitles.remove(title);

 752:         fireChartChanged();

 753:     }

 754:     

 755:     /**

 756:      * Returns the plot for the chart.  The plot is a class responsible for

 757:      * coordinating the visual representation of the data, including the axes

 758:      * (if any).

 759:      *

 760:      * @return The plot.

 761:      */

 762:     public Plot getPlot() {

 763:         return this.plot;

 764:     }

 765: 

 766:     /**

 767:      * Returns the plot cast as a {@link CategoryPlot}.

 768:      * <p>

 769:      * NOTE: if the plot is not an instance of {@link CategoryPlot}, then a

 770:      * <code>ClassCastException</code> is thrown.

 771:      *

 772:      * @return The plot.

 773:      * 

 774:      * @see #getPlot()

 775:      */

 776:     public CategoryPlot getCategoryPlot() {

 777:         return (CategoryPlot) this.plot;

 778:     }

 779: 

 780:     /**

 781:      * Returns the plot cast as an {@link XYPlot}.

 782:      * <p>

 783:      * NOTE: if the plot is not an instance of {@link XYPlot}, then a

 784:      * <code>ClassCastException</code> is thrown.

 785:      *

 786:      * @return The plot.

 787:      * 

 788:      * @see #getPlot()

 789:      */

 790:     public XYPlot getXYPlot() {

 791:         return (XYPlot) this.plot;

 792:     }

 793: 

 794:     /**

 795:      * Returns a flag that indicates whether or not anti-aliasing is used when

 796:      * the chart is drawn.

 797:      *

 798:      * @return The flag.

 799:      * 

 800:      * @see #setAntiAlias(boolean)

 801:      */

 802:     public boolean getAntiAlias() {

 803:         Object val = this.renderingHints.get(RenderingHints.KEY_ANTIALIASING);

 804:         return RenderingHints.VALUE_ANTIALIAS_ON.equals(val);

 805:     }

 806:     

 807:     /**

 808:      * Sets a flag that indicates whether or not anti-aliasing is used when the

 809:      * chart is drawn.

 810:      * <P>

 811:      * Anti-aliasing usually improves the appearance of charts, but is slower.

 812:      *

 813:      * @param flag  the new value of the flag.

 814:      * 

 815:      * @see #getAntiAlias()

 816:      */

 817:     public void setAntiAlias(boolean flag) {

 818: 

 819:         Object val = this.renderingHints.get(RenderingHints.KEY_ANTIALIASING);

 820:         if (val == null) {

 821:             val = RenderingHints.VALUE_ANTIALIAS_DEFAULT;

 822:         }

 823:         if (!flag && RenderingHints.VALUE_ANTIALIAS_OFF.equals(val) 

 824:             || flag && RenderingHints.VALUE_ANTIALIAS_ON.equals(val)) {

 825:             // no change, do nothing

 826:             return;

 827:         }

 828:         if (flag) {

 829:             this.renderingHints.put(RenderingHints.KEY_ANTIALIASING, 

 830:                                     RenderingHints.VALUE_ANTIALIAS_ON);

 831:         }

 832:         else {

 833:             this.renderingHints.put(RenderingHints.KEY_ANTIALIASING, 

 834:                                     RenderingHints.VALUE_ANTIALIAS_OFF);

 835:         }

 836:         fireChartChanged();

 837: 

 838:     }

 839: 

 840:     /**

 841:      * Returns the current value stored in the rendering hints table for

 842:      * {@link RenderingHints#KEY_TEXT_ANTIALIASING}.

 843:      * 

 844:      * @return The hint value (possibly <code>null</code>).

 845:      * 

 846:      * @since 1.0.5

 847:      * 

 848:      * @see #setTextAntiAlias(Object)

 849:      */

 850:     public Object getTextAntiAlias() {

 851:         return this.renderingHints.get(RenderingHints.KEY_TEXT_ANTIALIASING); 

 852:     }

 853:     

 854:     /**

 855:      * Sets the value in the rendering hints table for 

 856:      * {@link RenderingHints#KEY_TEXT_ANTIALIASING} to either

 857:      * {@link RenderingHints#VALUE_TEXT_ANTIALIAS_ON} or

 858:      * {@link RenderingHints#VALUE_TEXT_ANTIALIAS_OFF}, then sends a 

 859:      * {@link ChartChangeEvent} to all registered listeners.

 860:      * 

 861:      * @param flag

 862:      * 

 863:      * @since 1.0.5

 864:      * 

 865:      * @see #getTextAntiAlias()

 866:      * @see #setTextAntiAlias(Object)

 867:      */

 868:     public void setTextAntiAlias(boolean flag) {

 869:         if (flag) {

 870:             setTextAntiAlias(RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

 871:         }

 872:         else {

 873:             setTextAntiAlias(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);            

 874:         }

 875:     }

 876: 

 877:     /**

 878:      * Sets the value in the rendering hints table for 

 879:      * {@link RenderingHints#KEY_TEXT_ANTIALIASING} and sends a 

 880:      * {@link ChartChangeEvent} to all registered listeners.

 881:      * 

 882:      * @param val  the new value (<code>null</code> permitted).

 883:      * 

 884:      * @since 1.0.5

 885:      * 

 886:      * @see #getTextAntiAlias()

 887:      * @see #setTextAntiAlias(boolean)

 888:      */

 889:     public void setTextAntiAlias(Object val) {

 890:         this.renderingHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, val);

 891:         this.notifyListeners(new ChartChangeEvent(this));

 892:     }

 893:     

 894:     /**

 895:      * Returns the paint used for the chart background.

 896:      *

 897:      * @return The paint (possibly <code>null</code>).

 898:      * 

 899:      * @see #setBackgroundPaint(Paint)

 900:      */

 901:     public Paint getBackgroundPaint() {

 902:         return this.backgroundPaint;

 903:     }

 904: 

 905:     /**

 906:      * Sets the paint used to fill the chart background and sends a 

 907:      * {@link ChartChangeEvent} to all registered listeners.

 908:      *

 909:      * @param paint  the paint (<code>null</code> permitted).

 910:      * 

 911:      * @see #getBackgroundPaint()

 912:      */

 913:     public void setBackgroundPaint(Paint paint) {

 914: 

 915:         if (this.backgroundPaint != null) {

 916:             if (!this.backgroundPaint.equals(paint)) {

 917:                 this.backgroundPaint = paint;

 918:                 fireChartChanged();

 919:             }

 920:         }

 921:         else {

 922:             if (paint != null) {

 923:                 this.backgroundPaint = paint;

 924:                 fireChartChanged();

 925:             }

 926:         }

 927: 

 928:     }

 929: 

 930:     /**

 931:      * Returns the background image for the chart, or <code>null</code> if 

 932:      * there is no image.

 933:      *

 934:      * @return The image (possibly <code>null</code>).

 935:      * 

 936:      * @see #setBackgroundImage(Image)

 937:      */

 938:     public Image getBackgroundImage() {

 939:         return this.backgroundImage;

 940:     }

 941: 

 942:     /**

 943:      * Sets the background image for the chart and sends a 

 944:      * {@link ChartChangeEvent} to all registered listeners.

 945:      *

 946:      * @param image  the image (<code>null</code> permitted).

 947:      * 

 948:      * @see #getBackgroundImage()

 949:      */

 950:     public void setBackgroundImage(Image image) {

 951: 

 952:         if (this.backgroundImage != null) {

 953:             if (!this.backgroundImage.equals(image)) {

 954:                 this.backgroundImage = image;

 955:                 fireChartChanged();

 956:             }

 957:         }

 958:         else {

 959:             if (image != null) {

 960:                 this.backgroundImage = image;

 961:                 fireChartChanged();

 962:             }

 963:         }

 964: 

 965:     }

 966: 

 967:     /**

 968:      * Returns the background image alignment. Alignment constants are defined 

 969:      * in the <code>org.jfree.ui.Align</code> class in the JCommon class 

 970:      * library.

 971:      *

 972:      * @return The alignment.

 973:      * 

 974:      * @see #setBackgroundImageAlignment(int)

 975:      */

 976:     public int getBackgroundImageAlignment() {

 977:         return this.backgroundImageAlignment;

 978:     }

 979: 

 980:     /**

 981:      * Sets the background alignment.  Alignment options are defined by the 

 982:      * {@link org.jfree.ui.Align} class.

 983:      *

 984:      * @param alignment  the alignment.

 985:      * 

 986:      * @see #getBackgroundImageAlignment()

 987:      */

 988:     public void setBackgroundImageAlignment(int alignment) {

 989:         if (this.backgroundImageAlignment != alignment) {

 990:             this.backgroundImageAlignment = alignment;

 991:             fireChartChanged();

 992:         }

 993:     }

 994: 

 995:     /**

 996:      * Returns the alpha-transparency for the chart's background image.

 997:      *

 998:      * @return The alpha-transparency.

 999:      * 

1000:      * @see #setBackgroundImageAlpha(float)

1001:      */

1002:     public float getBackgroundImageAlpha() {

1003:         return this.backgroundImageAlpha;

1004:     }

1005: 

1006:     /**

1007:      * Sets the alpha-transparency for the chart's background image.

1008:      * Registered listeners are notified that the chart has been changed.

1009:      *

1010:      * @param alpha  the alpha value.

1011:      * 

1012:      * @see #getBackgroundImageAlpha()

1013:      */

1014:     public void setBackgroundImageAlpha(float alpha) {

1015: 

1016:         if (this.backgroundImageAlpha != alpha) {

1017:             this.backgroundImageAlpha = alpha;

1018:             fireChartChanged();

1019:         }

1020: 

1021:     }

1022: 

1023:     /**

1024:      * Returns a flag that controls whether or not change events are sent to 

1025:      * registered listeners.

1026:      *

1027:      * @return A boolean.

1028:      * 

1029:      * @see #setNotify(boolean)

1030:      */

1031:     public boolean isNotify() {

1032:         return this.notify;

1033:     }

1034: 

1035:     /**

1036:      * Sets a flag that controls whether or not listeners receive 

1037:      * {@link ChartChangeEvent} notifications.

1038:      *

1039:      * @param notify  a boolean.

1040:      * 

1041:      * @see #isNotify()

1042:      */

1043:     public void setNotify(boolean notify) {

1044:         this.notify = notify;

1045:         // if the flag is being set to true, there may be queued up changes...

1046:         if (notify) {

1047:             notifyListeners(new ChartChangeEvent(this));

1048:         }

1049:     }

1050: 

1051:     /**

1052:      * Draws the chart on a Java 2D graphics device (such as the screen or a

1053:      * printer).

1054:      * <P>

1055:      * This method is the focus of the entire JFreeChart library.

1056:      *

1057:      * @param g2  the graphics device.

1058:      * @param area  the area within which the chart should be drawn.

1059:      */

1060:     public void draw(Graphics2D g2, Rectangle2D area) {

1061:         draw(g2, area, null, null);

1062:     }

1063: 

1064:     /**

1065:      * Draws the chart on a Java 2D graphics device (such as the screen or a

1066:      * printer).  This method is the focus of the entire JFreeChart library.

1067:      *

1068:      * @param g2  the graphics device.

1069:      * @param area  the area within which the chart should be drawn.

1070:      * @param info  records info about the drawing (null means collect no info).

1071:      */

1072:     public void draw(Graphics2D g2, Rectangle2D area, ChartRenderingInfo info) {

1073:         draw(g2, area, null, info);

1074:     }

1075:     

1076:     /**

1077:      * Draws the chart on a Java 2D graphics device (such as the screen or a

1078:      * printer).

1079:      * <P>

1080:      * This method is the focus of the entire JFreeChart library.

1081:      *

1082:      * @param g2  the graphics device.

1083:      * @param chartArea  the area within which the chart should be drawn.

1084:      * @param anchor  the anchor point (in Java2D space) for the chart 

1085:      *                (<code>null</code> permitted).

1086:      * @param info  records info about the drawing (null means collect no info).

1087:      */

1088:     public void draw(Graphics2D g2, 

1089:                      Rectangle2D chartArea, Point2D anchor, 

1090:                      ChartRenderingInfo info) {

1091: 

1092:         notifyListeners(new ChartProgressEvent(this, this, 

1093:                 ChartProgressEvent.DRAWING_STARTED, 0));

1094: 

1095:         // record the chart area, if info is requested...

1096:         if (info != null) {

1097:             info.clear();

1098:             info.setChartArea(chartArea);

1099:         }

1100: 

1101:         // ensure no drawing occurs outside chart area...

1102:         Shape savedClip = g2.getClip();

1103:         g2.clip(chartArea);

1104: 

1105:         g2.addRenderingHints(this.renderingHints);

1106: 

1107:         // draw the chart background...

1108:         if (this.backgroundPaint != null) {

1109:             g2.setPaint(this.backgroundPaint);

1110:             g2.fill(chartArea);

1111:         }

1112: 

1113:         if (this.backgroundImage != null) {

1114:             Composite originalComposite = g2.getComposite();

1115:             g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 

1116:                     this.backgroundImageAlpha));

1117:             Rectangle2D dest = new Rectangle2D.Double(0.0, 0.0, 

1118:                     this.backgroundImage.getWidth(null), 

1119:                     this.backgroundImage.getHeight(null));

1120:             Align.align(dest, chartArea, this.backgroundImageAlignment);

1121:             g2.drawImage(this.backgroundImage, (int) dest.getX(), 

1122:                     (int) dest.getY(), (int) dest.getWidth(), 

1123:                     (int) dest.getHeight(), null);

1124:             g2.setComposite(originalComposite);

1125:         }

1126: 

1127:         if (isBorderVisible()) {

1128:             Paint paint = getBorderPaint();

1129:             Stroke stroke = getBorderStroke();

1130:             if (paint != null && stroke != null) {

1131:                 Rectangle2D borderArea = new Rectangle2D.Double(

1132:                         chartArea.getX(), chartArea.getY(), 

1133:                         chartArea.getWidth() - 1.0, chartArea.getHeight() 

1134:                         - 1.0);

1135:                 g2.setPaint(paint);

1136:                 g2.setStroke(stroke);

1137:                 g2.draw(borderArea);

1138:             }

1139:         }

1140: 

1141:         // draw the title and subtitles...

1142:         Rectangle2D nonTitleArea = new Rectangle2D.Double();

1143:         nonTitleArea.setRect(chartArea);

1144:         this.padding.trim(nonTitleArea);

1145:         

1146:         EntityCollection entities = null;

1147:         if (info != null) {

1148:             entities = info.getEntityCollection();   

1149:         }

1150:         if (this.title != null) {

1151:             EntityCollection e = drawTitle(this.title, g2, nonTitleArea, 

1152:                     (entities != null));

1153:             if (e != null) {

1154:                 entities.addAll(e);   

1155:             }

1156:         }

1157: 

1158:         Iterator iterator = this.subtitles.iterator();

1159:         while (iterator.hasNext()) {

1160:             Title currentTitle = (Title) iterator.next();

1161:             EntityCollection e = drawTitle(currentTitle, g2, nonTitleArea, 

1162:                     (entities != null));

1163:             if (e != null) {

1164:                 entities.addAll(e);   

1165:             }

1166:         }

1167: 

1168:         Rectangle2D plotArea = nonTitleArea;

1169:  

1170:         // draw the plot (axes and data visualisation)

1171:         PlotRenderingInfo plotInfo = null;

1172:         if (info != null) {

1173:             plotInfo = info.getPlotInfo();

1174:         }

1175:         this.plot.draw(g2, plotArea, anchor, null, plotInfo);

1176: 

1177:         g2.setClip(savedClip);

1178: 

1179:         notifyListeners(new ChartProgressEvent(this, this, 

1180:                 ChartProgressEvent.DRAWING_FINISHED, 100));

1181:     }

1182: 

1183:     /**

1184:      * Creates a rectangle that is aligned to the frame.

1185:      * 

1186:      * @param dimensions

1187:      * @param frame

1188:      * @param hAlign

1189:      * @param vAlign

1190:      * 

1191:      * @return A rectangle.

1192:      */

1193:     private Rectangle2D createAlignedRectangle2D(Size2D dimensions, 

1194:             Rectangle2D frame, HorizontalAlignment hAlign, 

1195:             VerticalAlignment vAlign) {

1196:         double x = Double.NaN;

1197:         double y = Double.NaN;

1198:         if (hAlign == HorizontalAlignment.LEFT) {

1199:             x = frame.getX();   

1200:         }

1201:         else if (hAlign == HorizontalAlignment.CENTER) {

1202:             x = frame.getCenterX() - (dimensions.width / 2.0);   

1203:         }

1204:         else if (hAlign == HorizontalAlignment.RIGHT) {

1205:             x = frame.getMaxX() - dimensions.width;   

1206:         }

1207:         if (vAlign == VerticalAlignment.TOP) {

1208:             y = frame.getY();   

1209:         }

1210:         else if (vAlign == VerticalAlignment.CENTER) {

1211:             y = frame.getCenterY() - (dimensions.height / 2.0);   

1212:         }

1213:         else if (vAlign == VerticalAlignment.BOTTOM) {

1214:             y = frame.getMaxY() - dimensions.height;   

1215:         }

1216:         

1217:         return new Rectangle2D.Double(x, y, dimensions.width, 

1218:                 dimensions.height);

1219:     }

1220:     

1221:     /**

1222:      * Draws a title.  The title should be drawn at the top, bottom, left or 

1223:      * right of the specified area, and the area should be updated to reflect 

1224:      * the amount of space used by the title.

1225:      *

1226:      * @param t  the title (<code>null</code> not permitted).

1227:      * @param g2  the graphics device (<code>null</code> not permitted).

1228:      * @param area  the chart area, excluding any existing titles 

1229:      *              (<code>null</code> not permitted).

1230:      * @param entities  a flag that controls whether or not an entity 

1231:      *                  collection is returned for the title.

1232:      * 

1233:      * @return An entity collection for the title (possibly <code>null</code>).

1234:      */

1235:     protected EntityCollection drawTitle(Title t, Graphics2D g2, 

1236:                                          Rectangle2D area, boolean entities) {

1237: 

1238:         if (t == null) {

1239:             throw new IllegalArgumentException("Null 't' argument.");   

1240:         }

1241:         if (area == null) {

1242:             throw new IllegalArgumentException("Null 'area' argument.");   

1243:         }

1244:         Rectangle2D titleArea = new Rectangle2D.Double();

1245:         RectangleEdge position = t.getPosition();

1246:         double ww = area.getWidth();

1247:         if (ww <= 0.0) {

1248:             return null;

1249:         }

1250:         double hh = area.getHeight();

1251:         if (hh <= 0.0) {

1252:             return null;

1253:         }

1254:         RectangleConstraint constraint = new RectangleConstraint(ww, 

1255:                 new Range(0.0, ww), LengthConstraintType.RANGE, hh, 

1256:                 new Range(0.0, hh), LengthConstraintType.RANGE);

1257:         Object retValue = null;

1258:         BlockParams p = new BlockParams();

1259:         p.setGenerateEntities(entities);

1260:         if (position == RectangleEdge.TOP) {

1261:             Size2D size = t.arrange(g2, constraint);

1262:             titleArea = createAlignedRectangle2D(size, area, 

1263:                     t.getHorizontalAlignment(), VerticalAlignment.TOP);

1264:             retValue = t.draw(g2, titleArea, p);

1265:             area.setRect(area.getX(), Math.min(area.getY() + size.height, 

1266:                     area.getMaxY()), area.getWidth(), Math.max(area.getHeight()

1267:                     - size.height, 0));

1268:         }

1269:         else if (position == RectangleEdge.BOTTOM) {

1270:             Size2D size = t.arrange(g2, constraint);

1271:             titleArea = createAlignedRectangle2D(size, area, 

1272:                     t.getHorizontalAlignment(), VerticalAlignment.BOTTOM);

1273:             retValue = t.draw(g2, titleArea, p);

1274:             area.setRect(area.getX(), area.getY(), area.getWidth(), 

1275:                     area.getHeight() - size.height);

1276:         }

1277:         else if (position == RectangleEdge.RIGHT) {

1278:             Size2D size = t.arrange(g2, constraint);

1279:             titleArea = createAlignedRectangle2D(size, area, 

1280:                     HorizontalAlignment.RIGHT, t.getVerticalAlignment());

1281:             retValue = t.draw(g2, titleArea, p);

1282:             area.setRect(area.getX(), area.getY(), area.getWidth() 

1283:                     - size.width, area.getHeight());

1284:         }

1285: 

1286:         else if (position == RectangleEdge.LEFT) {

1287:             Size2D size = t.arrange(g2, constraint);

1288:             titleArea = createAlignedRectangle2D(size, area, 

1289:                     HorizontalAlignment.LEFT, t.getVerticalAlignment());

1290:             retValue = t.draw(g2, titleArea, p);

1291:             area.setRect(area.getX() + size.width, area.getY(), area.getWidth() 

1292:                     - size.width, area.getHeight());

1293:         }

1294:         else {

1295:             throw new RuntimeException("Unrecognised title position.");

1296:         }

1297:         EntityCollection result = null;

1298:         if (retValue instanceof EntityBlockResult) {

1299:             EntityBlockResult ebr = (EntityBlockResult) retValue;

1300:             result = ebr.getEntityCollection();

1301:         }

1302:         return result;   

1303:     }

1304: 

1305:     /**

1306:      * Creates and returns a buffered image into which the chart has been drawn.

1307:      *

1308:      * @param width  the width.

1309:      * @param height  the height.

1310:      *

1311:      * @return A buffered image.

1312:      */

1313:     public BufferedImage createBufferedImage(int width, int height) {

1314:         return createBufferedImage(width, height, null);

1315:     }

1316: 

1317:     /**

1318:      * Creates and returns a buffered image into which the chart has been drawn.

1319:      *

1320:      * @param width  the width.

1321:      * @param height  the height.

1322:      * @param info  carries back chart state information (<code>null</code> 

1323:      *              permitted).

1324:      *

1325:      * @return A buffered image.

1326:      */

1327:     public BufferedImage createBufferedImage(int width, int height, 

1328:                                              ChartRenderingInfo info) {

1329:         return createBufferedImage(width, height, BufferedImage.TYPE_INT_RGB, 

1330:                 info);

1331:     }

1332: 

1333:     /**

1334:      * Creates and returns a buffered image into which the chart has been drawn.

1335:      *

1336:      * @param width  the width.

1337:      * @param height  the height.

1338:      * @param imageType  the image type.

1339:      * @param info  carries back chart state information (<code>null</code> 

1340:      *              permitted).

1341:      *

1342:      * @return A buffered image.

1343:      */

1344:     public BufferedImage createBufferedImage(int width, int height, 

1345:                                              int imageType, 

1346:                                              ChartRenderingInfo info) {

1347:         BufferedImage image = new BufferedImage(width, height, imageType);

1348:         Graphics2D g2 = image.createGraphics();

1349:         draw(g2, new Rectangle2D.Double(0, 0, width, height), null, info);

1350:         g2.dispose();

1351:         return image;

1352:     }

1353: 

1354:     /**

1355:      * Creates and returns a buffered image into which the chart has been drawn.

1356:      *

1357:      * @param imageWidth  the image width.

1358:      * @param imageHeight  the image height.

1359:      * @param drawWidth  the width for drawing the chart (will be scaled to 

1360:      *                   fit image).

1361:      * @param drawHeight  the height for drawing the chart (will be scaled to 

1362:      *                    fit image).

1363:      * @param info  optional object for collection chart dimension and entity 

1364:      *              information.

1365:      *

1366:      * @return A buffered image.

1367:      */

1368:     public BufferedImage createBufferedImage(int imageWidth, 

1369:                                              int imageHeight,

1370:                                              double drawWidth, 

1371:                                              double drawHeight, 

1372:                                              ChartRenderingInfo info) {

1373: 

1374:         BufferedImage image = new BufferedImage(imageWidth, imageHeight, 

1375:                 BufferedImage.TYPE_INT_RGB);

1376:         Graphics2D g2 = image.createGraphics();

1377:         double scaleX = imageWidth / drawWidth;

1378:         double scaleY = imageHeight / drawHeight;

1379:         AffineTransform st = AffineTransform.getScaleInstance(scaleX, scaleY);

1380:         g2.transform(st);

1381:         draw(g2, new Rectangle2D.Double(0, 0, drawWidth, drawHeight), null, 

1382:                 info);

1383:         g2.dispose();

1384:         return image;

1385: 

1386:     }

1387: 

1388:     /**

1389:      * Handles a 'click' on the chart.

1390:      * <P>

1391:      * JFreeChart is not a UI component, so some other object (e.g. ChartPanel)

1392:      * needs to capture the click event and pass it onto the JFreeChart object.

1393:      * If you are not using JFreeChart in a client application, then this

1394:      * method is not required (and hopefully it doesn't get in the way).

1395:      *

1396:      * @param x  x-coordinate of the click (in Java2D space).

1397:      * @param y  y-coordinate of the click (in Java2D space).

1398:      * @param info  contains chart dimension and entity information.

1399:      */

1400:     public void handleClick(int x, int y, ChartRenderingInfo info) {

1401: 

1402:         // pass the click on to the plot...

1403:         // rely on the plot to post a plot change event and redraw the chart...

1404:         this.plot.handleClick(x, y, info.getPlotInfo());

1405: 

1406:     }

1407: 

1408:     /**

1409:      * Registers an object for notification of changes to the chart.

1410:      *

1411:      * @param listener  the listener (<code>null</code> not permitted).

1412:      * 

1413:      * @see #removeChangeListener(ChartChangeListener)

1414:      */

1415:     public void addChangeListener(ChartChangeListener listener) {

1416:         if (listener == null) {

1417:             throw new IllegalArgumentException("Null 'listener' argument.");

1418:         }

1419:         this.changeListeners.add(ChartChangeListener.class, listener);

1420:     }

1421: 

1422:     /**

1423:      * Deregisters an object for notification of changes to the chart.

1424:      *

1425:      * @param listener  the listener (<code>null</code> not permitted)

1426:      * 

1427:      * @see #addChangeListener(ChartChangeListener)

1428:      */

1429:     public void removeChangeListener(ChartChangeListener listener) {

1430:         if (listener == null) {

1431:             throw new IllegalArgumentException("Null 'listener' argument.");

1432:         }

1433:         this.changeListeners.remove(ChartChangeListener.class, listener);

1434:     }

1435: 

1436:     /**

1437:      * Sends a default {@link ChartChangeEvent} to all registered listeners.

1438:      * <P>

1439:      * This method is for convenience only.

1440:      */

1441:     public void fireChartChanged() {

1442:         ChartChangeEvent event = new ChartChangeEvent(this);

1443:         notifyListeners(event);

1444:     }

1445: 

1446:     /**

1447:      * Sends a {@link ChartChangeEvent} to all registered listeners.

1448:      *

1449:      * @param event  information about the event that triggered the 

1450:      *               notification.

1451:      */

1452:     protected void notifyListeners(ChartChangeEvent event) {

1453:         if (this.notify) {

1454:             Object[] listeners = this.changeListeners.getListenerList();

1455:             for (int i = listeners.length - 2; i >= 0; i -= 2) {

1456:                 if (listeners[i] == ChartChangeListener.class) {

1457:                     ((ChartChangeListener) listeners[i + 1]).chartChanged(

1458:                             event);

1459:                 }

1460:             }

1461:         }

1462:     }

1463: 

1464:     /**

1465:      * Registers an object for notification of progress events relating to the 

1466:      * chart.

1467:      *

1468:      * @param listener  the object being registered.

1469:      * 

1470:      * @see #removeProgressListener(ChartProgressListener)

1471:      */

1472:     public void addProgressListener(ChartProgressListener listener) {

1473:         this.progressListeners.add(ChartProgressListener.class, listener);

1474:     }

1475: 

1476:     /**

1477:      * Deregisters an object for notification of changes to the chart.

1478:      *

1479:      * @param listener  the object being deregistered.

1480:      * 

1481:      * @see #addProgressListener(ChartProgressListener)

1482:      */

1483:     public void removeProgressListener(ChartProgressListener listener) {

1484:         this.progressListeners.remove(ChartProgressListener.class, listener);

1485:     }

1486: 

1487:     /**

1488:      * Sends a {@link ChartProgressEvent} to all registered listeners.

1489:      *

1490:      * @param event  information about the event that triggered the 

1491:      *               notification.

1492:      */

1493:     protected void notifyListeners(ChartProgressEvent event) {

1494: 

1495:         Object[] listeners = this.progressListeners.getListenerList();

1496:         for (int i = listeners.length - 2; i >= 0; i -= 2) {

1497:             if (listeners[i] == ChartProgressListener.class) {

1498:                 ((ChartProgressListener) listeners[i + 1]).chartProgress(event);

1499:             }

1500:         }

1501: 

1502:     }

1503: 

1504:     /**

1505:      * Receives notification that a chart title has changed, and passes this

1506:      * on to registered listeners.

1507:      *

1508:      * @param event  information about the chart title change.

1509:      */

1510:     public void titleChanged(TitleChangeEvent event) {

1511:         event.setChart(this);

1512:         notifyListeners(event);

1513:     }

1514: 

1515:     /**

1516:      * Receives notification that the plot has changed, and passes this on to

1517:      * registered listeners.

1518:      *

1519:      * @param event  information about the plot change.

1520:      */

1521:     public void plotChanged(PlotChangeEvent event) {

1522:         event.setChart(this);

1523:         notifyListeners(event);

1524:     }

1525: 

1526:     /**

1527:      * Tests this chart for equality with another object.

1528:      *

1529:      * @param obj  the object (<code>null</code> permitted).

1530:      *

1531:      * @return A boolean.

1532:      */

1533:     public boolean equals(Object obj) {

1534:         if (obj == this) {

1535:             return true;

1536:         }

1537:         if (!(obj instanceof JFreeChart)) {

1538:             return false;

1539:         }

1540:         JFreeChart that = (JFreeChart) obj;

1541:         if (!this.renderingHints.equals(that.renderingHints)) {

1542:             return false;   

1543:         }

1544:         if (this.borderVisible != that.borderVisible) {

1545:             return false;   

1546:         }

1547:         if (!ObjectUtilities.equal(this.borderStroke, that.borderStroke)) {

1548:             return false;   

1549:         }

1550:         if (!PaintUtilities.equal(this.borderPaint, that.borderPaint)) {

1551:             return false;   

1552:         }

1553:         if (!this.padding.equals(that.padding)) {

1554:             return false;   

1555:         }

1556:         if (!ObjectUtilities.equal(this.title, that.title)) {

1557:             return false;

1558:         }

1559:         if (!ObjectUtilities.equal(this.subtitles, that.subtitles)) {

1560:             return false;

1561:         }

1562:         if (!ObjectUtilities.equal(this.plot, that.plot)) {

1563:             return false;

1564:         }

1565:         if (!PaintUtilities.equal(

1566:             this.backgroundPaint, that.backgroundPaint

1567:         )) {

1568:             return false;

1569:         }

1570:         if (!ObjectUtilities.equal(this.backgroundImage, 

1571:                 that.backgroundImage)) {

1572:             return false;

1573:         }

1574:         if (this.backgroundImageAlignment != that.backgroundImageAlignment) {

1575:             return false;

1576:         }

1577:         if (this.backgroundImageAlpha != that.backgroundImageAlpha) {

1578:             return false;

1579:         }

1580:         if (this.notify != that.notify) {

1581:             return false;

1582:         }

1583:         return true;

1584:     }

1585: 

1586:     /**

1587:      * Provides serialization support.

1588:      *

1589:      * @param stream  the output stream.

1590:      *

1591:      * @throws IOException  if there is an I/O error.

1592:      */

1593:     private void writeObject(ObjectOutputStream stream) throws IOException {

1594:         stream.defaultWriteObject();

1595:         SerialUtilities.writeStroke(this.borderStroke, stream);

1596:         SerialUtilities.writePaint(this.borderPaint, stream);

1597:         SerialUtilities.writePaint(this.backgroundPaint, stream);

1598:     }

1599: 

1600:     /**

1601:      * Provides serialization support.

1602:      *

1603:      * @param stream  the input stream.

1604:      *

1605:      * @throws IOException  if there is an I/O error.

1606:      * @throws ClassNotFoundException  if there is a classpath problem.

1607:      */

1608:     private void readObject(ObjectInputStream stream) 

1609:         throws IOException, ClassNotFoundException {

1610:         stream.defaultReadObject();

1611:         this.borderStroke = SerialUtilities.readStroke(stream);

1612:         this.borderPaint = SerialUtilities.readPaint(stream);

1613:         this.backgroundPaint = SerialUtilities.readPaint(stream);

1614:         this.progressListeners = new EventListenerList();

1615:         this.changeListeners = new EventListenerList();

1616:         this.renderingHints = new RenderingHints(

1617:                 RenderingHints.KEY_ANTIALIASING, 

1618:                 RenderingHints.VALUE_ANTIALIAS_ON);

1619: 

1620:         // register as a listener with sub-components...

1621:         if (this.title != null) {

1622:             this.title.addChangeListener(this);

1623:         }

1624: 

1625:         for (int i = 0; i < getSubtitleCount(); i++) {

1626:             getSubtitle(i).addChangeListener(this);

1627:         }

1628:         this.plot.addChangeListener(this);

1629:     }

1630: 

1631:     /**

1632:      * Prints information about JFreeChart to standard output.

1633:      *

1634:      * @param args  no arguments are honored.

1635:      */

1636:     public static void main(String[] args) {

1637:         System.out.println(JFreeChart.INFO.toString());

1638:     }

1639: 

1640:     /**

1641:      * Clones the object, and takes care of listeners.

1642:      * Note: caller shall register its own listeners on cloned graph.

1643:      * 

1644:      * @return A clone.

1645:      * 

1646:      * @throws CloneNotSupportedException if the chart is not cloneable.

1647:      */

1648:     public Object clone() throws CloneNotSupportedException {

1649:         JFreeChart chart = (JFreeChart) super.clone();

1650: 

1651:         chart.renderingHints = (RenderingHints) this.renderingHints.clone();

1652:         // private boolean borderVisible;

1653:         // private transient Stroke borderStroke;

1654:         // private transient Paint borderPaint;

1655: 

1656:         if (this.title != null) {

1657:             chart.title = (TextTitle) this.title.clone();

1658:             chart.title.addChangeListener(chart);

1659:         }

1660: 

1661:         chart.subtitles = new ArrayList();

1662:         for (int i = 0; i < getSubtitleCount(); i++) {

1663:             Title subtitle = (Title) getSubtitle(i).clone();

1664:             chart.subtitles.add(subtitle);

1665:             subtitle.addChangeListener(chart);

1666:         }

1667: 

1668:         if (this.plot != null) {

1669:             chart.plot = (Plot) this.plot.clone();

1670:             chart.plot.addChangeListener(chart);

1671:         }

1672: 

1673:         chart.progressListeners = new EventListenerList();

1674:         chart.changeListeners = new EventListenerList();

1675:         return chart;

1676:     }

1677: 

1678: }

1679: 

1680: /**

1681:  * Information about the JFreeChart project.  One instance of this class is 

1682:  * assigned to <code>JFreeChart.INFO<code>.

1683:  */

1684: class JFreeChartInfo extends ProjectInfo {

1685: 

1686:     /** 

1687:      * Default constructor. 

1688:      */

1689:     public JFreeChartInfo() {

1690: 

1691:         // get a locale-specific resource bundle...

1692:         String baseResourceClass 

1693:             = "org.jfree.chart.resources.JFreeChartResources";

1694:         ResourceBundle resources = ResourceBundle.getBundle(baseResourceClass);

1695: 

1696:         setName(resources.getString("project.name"));

1697:         setVersion(resources.getString("project.version"));

1698:         setInfo(resources.getString("project.info"));

1699:         setCopyright(resources.getString("project.copyright"));

1700:         setLogo(null);  // load only when required

1701:         setLicenceName("LGPL");

1702:         setLicenceText(Licences.getInstance().getLGPL());

1703: 

1704:         setContributors(Arrays.asList(

1705:             new Contributor[]{

1706:                 new Contributor("Eric Alexander", "-"),

1707:                 new Contributor(

1708:                     "Richard Atkinson", "[email protected]"

1709:                 ),

1710:                 new Contributor("David Basten", "-"),

1711:                 new Contributor("David Berry", "-"),

1712:                 new Contributor("Anthony Boulestreau", "-"),

1713:                 new Contributor("Jeremy Bowman", "-"),

1714:                 new Contributor("Nicolas Brodu", "-"),

1715:                 new Contributor("David Browning", "-"),

1716:                 new Contributor("Soren Caspersen", "-"),

1717:                 new Contributor("Chuanhao Chiu", "-"),

1718:                 new Contributor("Brian Cole", "-"),

1719:                 new Contributor("Pascal Collet", "-"),

1720:                 new Contributor("Martin Cordova", "-"),

1721:                 new Contributor("Paolo Cova", "-"),

1722:                 new Contributor("Mike Duffy", "-"),

1723:                 new Contributor("Don Elliott", "-"),

1724:                 new Contributor("Jonathan Gabbai", "-"),

1725:                 new Contributor("David Gilbert", 

1726:                         "[email protected]"),

1727:                 new Contributor("Serge V. Grachov", "-"),

1728:                 new Contributor("Daniel Gredler", "-"),

1729:                 new Contributor("Hans-Jurgen Greiner", "-"),

1730:                 new Contributor("Joao Guilherme Del Valle", "-"),

1731:                 new Contributor("Aiman Han", "-"),

1732:                 new Contributor("Cameron Hayne", "-"),

1733:                 new Contributor("Jon Iles", "-"),

1734:                 new Contributor("Wolfgang Irler", "-"),

1735:                 new Contributor("Sergei Ivanov", "-"),

1736:                 new Contributor("Adriaan Joubert", "-"),

1737:                 new Contributor("Darren Jung", "-"),

1738:                 new Contributor("Xun Kang", "-"),

1739:                 new Contributor("Bill Kelemen", "-"),

1740:                 new Contributor("Norbert Kiesel", "-"),

1741:                 new Contributor("Gideon Krause", "-"),

1742:                 new Contributor("Pierre-Marie Le Biot", "-"),

1743:                 new Contributor("Arnaud Lelievre", "-"),

1744:                 new Contributor("Wolfgang Lenhard", "-"),

1745:                 new Contributor("David Li", "-"),

1746:                 new Contributor("Yan Liu", "-"),

1747:                 new Contributor("Tin Luu", "-"),

1748:                 new Contributor("Craig MacFarlane", "-"),

1749:                 new Contributor("Achilleus Mantzios", "-"),

1750:                 new Contributor("Thomas Meier", "-"),

1751:                 new Contributor("Jim Moore", "-"),

1752:                 new Contributor("Jonathan Nash", "-"),

1753:                 new Contributor("Barak Naveh", "-"),

1754:                 new Contributor("David M. O'Donnell", "-"),

1755:                 new Contributor("Krzysztof Paz", "-"),

1756:                 new Contributor("Tomer Peretz", "-"),

1757:                 new Contributor("Andrzej Porebski", "-"),

1758:                 new Contributor("Xavier Poinsard", "-"),

1759:                 new Contributor("Viktor Rajewski", "-"),

1760:                 new Contributor("Eduardo Ramalho", "-"),

1761:                 new Contributor("Michael Rauch", "-"),

1762:                 new Contributor("Cameron Riley", "-"),

1763:                 new Contributor("Klaus Rheinwald", "-"),

1764:                 new Contributor("Dan Rivett", "[email protected]"),

1765:                 new Contributor("Scott Sams", "-"),

1766:                 new Contributor("Michel Santos", "-"),

1767:                 new Contributor("Thierry Saura", "-"),

1768:                 new Contributor("Andreas Schneider", "-"),

1769:                 new Contributor("Jean-Luc SCHWAB", "-"),

1770:                 new Contributor("Bryan Scott", "-"),

1771:                 new Contributor("Tobias Selb", "-"),

1772:                 new Contributor("Mofeed Shahin", "-"),

1773:                 new Contributor("Pady Srinivasan", "-"),

1774:                 new Contributor("Greg Steckman", "-"),

1775:                 new Contributor("Roger Studner", "-"),

1776:                 new Contributor("Irv Thomae", "-"),

1777:                 new Contributor("Eric Thomas", "-"),

1778:                 new Contributor("Rich Unger", "-"),

1779:                 new Contributor("Daniel van Enckevort", "-"),

1780:                 new Contributor("Laurence Vanhelsuwe", "-"),

1781:                 new Contributor("Sylvain Vieujot", "-"),

1782:                 new Contributor("Mark Watson", "www.markwatson.com"),

1783:                 new Contributor("Alex Weber", "-"),

1784:                 new Contributor("Matthew Wright", "-"),

1785:                 new Contributor("Benoit Xhenseval", "-"),

1786:                 new Contributor("Christian W. Zuckschwerdt", 

1787:                         "[email protected]"),

1788:                 new Contributor("Hari", "-"),

1789:                 new Contributor("Sam (oldman)", "-"),

1790:             }

1791:         ));

1792: 

1793:         addLibrary(JCommon.INFO);

1794: 

1795:     }

1796: 

1797:     /**

1798:      * Returns the JFreeChart logo (a picture of a gorilla).

1799:      *

1800:      * @return The JFreeChart logo.

1801:      */

1802:     public Image getLogo() {

1803: 

1804:         Image logo = super.getLogo();

1805:         if (logo == null) {

1806:             URL imageURL = this.getClass().getClassLoader().getResource(

1807:                     "org/jfree/chart/gorilla.jpg");

1808:             if (imageURL != null) {

1809:                 ImageIcon temp = new ImageIcon(imageURL);  

1810:                     // use ImageIcon because it waits for the image to load...

1811:                 logo = temp.getImage();

1812:                 setLogo(logo);

1813:             }

1814:         }

1815:         return logo;

1816: 

1817:     }

1818: 

1819: }

Overview Package Class Use Source Tree Index Deprecated About

 

你可能感兴趣的:(jfreechart)