Source for org.jfree.chart.plot.Plot

   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:  * Plot.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):   Sylvain Vieujot;
  34:  *                   Jeremy Bowman;
  35:  *                   Andreas Schneider;
  36:  *                   Gideon Krause;
  37:  *                   Nicolas Brodu;
  38:  *                   Michal Krause;
  39:  *
  40:  * $Id: Plot.java,v 1.18.2.6 2007/01/11 11:32:57 mungady Exp $
  41:  *
  42:  * Changes (from 21-Jun-2001)
  43:  * --------------------------
  44:  * 21-Jun-2001 : Removed redundant JFreeChart parameter from constructors (DG);
  45:  * 18-Sep-2001 : Updated header info and fixed DOS encoding problem (DG);
  46:  * 19-Oct-2001 : Moved series paint and stroke methods from JFreeChart 
  47:  *               class (DG);
  48:  * 23-Oct-2001 : Created renderer for LinePlot class (DG);
  49:  * 07-Nov-2001 : Changed type names for ChartChangeEvent (DG);
  50:  *               Tidied up some Javadoc comments (DG);
  51:  * 13-Nov-2001 : Changes to allow for null axes on plots such as PiePlot (DG);
  52:  *               Added plot/axis compatibility checks (DG);
  53:  * 12-Dec-2001 : Changed constructors to protected, and removed unnecessary 
  54:  *               'throws' clauses (DG);
  55:  * 13-Dec-2001 : Added tooltips (DG);
  56:  * 22-Jan-2002 : Added handleClick() method, as part of implementation for 
  57:  *               crosshairs (DG);
  58:  *               Moved tooltips reference into ChartInfo class (DG);
  59:  * 23-Jan-2002 : Added test for null axes in chartChanged() method, thanks 
  60:  *               to Barry Evans for the bug report (number 506979 on 
  61:  *               SourceForge) (DG);
  62:  *               Added a zoom() method (DG);
  63:  * 05-Feb-2002 : Updated setBackgroundPaint(), setOutlineStroke() and 
  64:  *               setOutlinePaint() to better handle null values, as suggested 
  65:  *               by Sylvain Vieujot (DG);
  66:  * 06-Feb-2002 : Added background image, plus alpha transparency for background
  67:  *               and foreground (DG);
  68:  * 06-Mar-2002 : Added AxisConstants interface (DG);
  69:  * 26-Mar-2002 : Changed zoom method from empty to abstract (DG);
  70:  * 23-Apr-2002 : Moved dataset from JFreeChart class (DG);
  71:  * 11-May-2002 : Added ShapeFactory interface for getShape() methods, 
  72:  *               contributed by Jeremy Bowman (DG);
  73:  * 28-May-2002 : Fixed bug in setSeriesPaint(int, Paint) for subplots (AS);
  74:  * 25-Jun-2002 : Removed redundant imports (DG);
  75:  * 30-Jul-2002 : Added 'no data' message for charts with null or empty 
  76:  *               datasets (DG);
  77:  * 21-Aug-2002 : Added code to extend series array if necessary (refer to 
  78:  *               SourceForge bug id 594547 for details) (DG);
  79:  * 17-Sep-2002 : Fixed bug in getSeriesOutlineStroke() method, reported by 
  80:  *               Andreas Schroeder (DG);
  81:  * 23-Sep-2002 : Added getLegendItems() abstract method (DG);
  82:  * 24-Sep-2002 : Removed firstSeriesIndex, subplots now use their own paint 
  83:  *               settings, there is a new mechanism for the legend to collect 
  84:  *               the legend items (DG);
  85:  * 27-Sep-2002 : Added dataset group (DG);
  86:  * 14-Oct-2002 : Moved listener storage into EventListenerList.  Changed some 
  87:  *               abstract methods to empty implementations (DG);
  88:  * 28-Oct-2002 : Added a getBackgroundImage() method (DG);
  89:  * 21-Nov-2002 : Added a plot index for identifying subplots in combined and 
  90:  *               overlaid charts (DG);
  91:  * 22-Nov-2002 : Changed all attributes from 'protected' to 'private'.  Added 
  92:  *               dataAreaRatio attribute from David M O'Donnell's code (DG);
  93:  * 09-Jan-2003 : Integrated fix for plot border contributed by Gideon 
  94:  *               Krause (DG);
  95:  * 17-Jan-2003 : Moved to com.jrefinery.chart.plot (DG);
  96:  * 23-Jan-2003 : Removed one constructor (DG);
  97:  * 26-Mar-2003 : Implemented Serializable (DG);
  98:  * 14-Jul-2003 : Moved the dataset and secondaryDataset attributes to the 
  99:  *               CategoryPlot and XYPlot classes (DG);
 100:  * 21-Jul-2003 : Moved DrawingSupplier from CategoryPlot and XYPlot up to this 
 101:  *               class (DG);
 102:  * 20-Aug-2003 : Implemented Cloneable (DG);
 103:  * 11-Sep-2003 : Listeners and clone (NB);
 104:  * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
 105:  * 03-Dec-2003 : Modified draw method to accept anchor (DG);
 106:  * 12-Mar-2004 : Fixed clipping bug in drawNoDataMessage() method (DG);
 107:  * 07-Apr-2004 : Modified string bounds calculation (DG);
 108:  * 04-Nov-2004 : Added default shapes for legend items (DG);
 109:  * 25-Nov-2004 : Some changes to the clone() method implementation (DG);
 110:  * 23-Feb-2005 : Implemented new LegendItemSource interface (and also
 111:  *               PublicCloneable) (DG);
 112:  * 21-Apr-2005 : Replaced Insets with RectangleInsets (DG);
 113:  * 05-May-2005 : Removed unused draw() method (DG);
 114:  * 06-Jun-2005 : Fixed bugs in equals() method (DG);
 115:  * 01-Sep-2005 : Moved dataAreaRatio from here to ContourPlot (DG);
 116:  * ------------- JFREECHART 1.0.x ---------------------------------------------
 117:  * 30-Jun-2006 : Added background image alpha - see bug report 1514904 (DG);
 118:  * 05-Sep-2006 : Implemented the MarkerChangeListener interface (DG);
 119:  * 11-Jan-2007 : Added some argument checks, event notifications, and many
 120:  *               API doc updates (DG);
 121:  *
 122:  */
 123: 
 124: package org.jfree.chart.plot;
 125: 
 126: import java.awt.AlphaComposite;
 127: import java.awt.BasicStroke;
 128: import java.awt.Color;
 129: import java.awt.Composite;
 130: import java.awt.Font;
 131: import java.awt.Graphics2D;
 132: import java.awt.Image;
 133: import java.awt.Paint;
 134: import java.awt.Shape;
 135: import java.awt.Stroke;
 136: import java.awt.geom.Ellipse2D;
 137: import java.awt.geom.Point2D;
 138: import java.awt.geom.Rectangle2D;
 139: import java.io.IOException;
 140: import java.io.ObjectInputStream;
 141: import java.io.ObjectOutputStream;
 142: import java.io.Serializable;
 143: 
 144: import javax.swing.event.EventListenerList;
 145: 
 146: import org.jfree.chart.LegendItemCollection;
 147: import org.jfree.chart.LegendItemSource;
 148: import org.jfree.chart.axis.AxisLocation;
 149: import org.jfree.chart.event.AxisChangeEvent;
 150: import org.jfree.chart.event.AxisChangeListener;
 151: import org.jfree.chart.event.ChartChangeEventType;
 152: import org.jfree.chart.event.MarkerChangeEvent;
 153: import org.jfree.chart.event.MarkerChangeListener;
 154: import org.jfree.chart.event.PlotChangeEvent;
 155: import org.jfree.chart.event.PlotChangeListener;
 156: import org.jfree.data.general.DatasetChangeEvent;
 157: import org.jfree.data.general.DatasetChangeListener;
 158: import org.jfree.data.general.DatasetGroup;
 159: import org.jfree.io.SerialUtilities;
 160: import org.jfree.text.G2TextMeasurer;
 161: import org.jfree.text.TextBlock;
 162: import org.jfree.text.TextBlockAnchor;
 163: import org.jfree.text.TextUtilities;
 164: import org.jfree.ui.Align;
 165: import org.jfree.ui.RectangleEdge;
 166: import org.jfree.ui.RectangleInsets;
 167: import org.jfree.util.ObjectUtilities;
 168: import org.jfree.util.PaintUtilities;
 169: import org.jfree.util.PublicCloneable;
 170: 
 171: /**
 172:  * The base class for all plots in JFreeChart.  The 
 173:  * {@link org.jfree.chart.JFreeChart} class delegates the drawing of axes and 
 174:  * data to the plot.  This base class provides facilities common to most plot 
 175:  * types.
 176:  */
 177: public abstract class Plot implements AxisChangeListener,
 178:                                       DatasetChangeListener,
 179:                                       MarkerChangeListener,
 180:                                       LegendItemSource,
 181:                                       PublicCloneable,
 182:                                       Cloneable,
 183:                                       Serializable {
 184: 
 185:     /** For serialization. */
 186:     private static final long serialVersionUID = -8831571430103671324L;
 187:     
 188:     /** Useful constant representing zero. */
 189:     public static final Number ZERO = new Integer(0);
 190: 
 191:     /** The default insets. */
 192:     public static final RectangleInsets DEFAULT_INSETS 
 193:         = new RectangleInsets(4.0, 8.0, 4.0, 8.0);
 194: 
 195:     /** The default outline stroke. */
 196:     public static final Stroke DEFAULT_OUTLINE_STROKE = new BasicStroke(0.5f);
 197: 
 198:     /** The default outline color. */
 199:     public static final Paint DEFAULT_OUTLINE_PAINT = Color.gray;
 200: 
 201:     /** The default foreground alpha transparency. */
 202:     public static final float DEFAULT_FOREGROUND_ALPHA = 1.0f;
 203: 
 204:     /** The default background alpha transparency. */
 205:     public static final float DEFAULT_BACKGROUND_ALPHA = 1.0f;
 206: 
 207:     /** The default background color. */
 208:     public static final Paint DEFAULT_BACKGROUND_PAINT = Color.white;
 209: 
 210:     /** The minimum width at which the plot should be drawn. */
 211:     public static final int MINIMUM_WIDTH_TO_DRAW = 10;
 212: 
 213:     /** The minimum height at which the plot should be drawn. */
 214:     public static final int MINIMUM_HEIGHT_TO_DRAW = 10;
 215:     
 216:     /** A default box shape for legend items. */
 217:     public static final Shape DEFAULT_LEGEND_ITEM_BOX 
 218:         = new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0);
 219:     
 220:     /** A default circle shape for legend items. */
 221:     public static final Shape DEFAULT_LEGEND_ITEM_CIRCLE 
 222:         = new Ellipse2D.Double(-4.0, -4.0, 8.0, 8.0);
 223: 
 224:     /** The parent plot (<code>null</code> if this is the root plot). */
 225:     private Plot parent;
 226: 
 227:     /** The dataset group (to be used for thread synchronisation). */
 228:     private DatasetGroup datasetGroup;
 229: 
 230:     /** The message to display if no data is available. */
 231:     private String noDataMessage;
 232: 
 233:     /** The font used to display the 'no data' message. */
 234:     private Font noDataMessageFont;
 235: 
 236:     /** The paint used to draw the 'no data' message. */
 237:     private transient Paint noDataMessagePaint;
 238: 
 239:     /** Amount of blank space around the plot area. */
 240:     private RectangleInsets insets;
 241: 
 242:     /** The Stroke used to draw an outline around the plot. */
 243:     private transient Stroke outlineStroke;
 244: 
 245:     /** The Paint used to draw an outline around the plot. */
 246:     private transient Paint outlinePaint;
 247: 
 248:     /** An optional color used to fill the plot background. */
 249:     private transient Paint backgroundPaint;
 250: 
 251:     /** An optional image for the plot background. */
 252:     private transient Image backgroundImage;  // not currently serialized
 253: 
 254:     /** The alignment for the background image. */
 255:     private int backgroundImageAlignment = Align.FIT;
 256: 
 257:     /** The alpha value used to draw the background image. */
 258:     private float backgroundImageAlpha = 0.5f;
 259:     
 260:     /** The alpha-transparency for the plot. */
 261:     private float foregroundAlpha;
 262: 
 263:     /** The alpha transparency for the background paint. */
 264:     private float backgroundAlpha;
 265: 
 266:     /** The drawing supplier. */
 267:     private DrawingSupplier drawingSupplier;
 268: 
 269:     /** Storage for registered change listeners. */
 270:     private transient EventListenerList listenerList;
 271: 
 272:     /**
 273:      * Creates a new plot.
 274:      */
 275:     protected Plot() {
 276: 
 277:         this.parent = null;
 278:         this.insets = DEFAULT_INSETS;
 279:         this.backgroundPaint = DEFAULT_BACKGROUND_PAINT;
 280:         this.backgroundAlpha = DEFAULT_BACKGROUND_ALPHA;
 281:         this.backgroundImage = null;
 282:         this.outlineStroke = DEFAULT_OUTLINE_STROKE;
 283:         this.outlinePaint = DEFAULT_OUTLINE_PAINT;
 284:         this.foregroundAlpha = DEFAULT_FOREGROUND_ALPHA;
 285: 
 286:         this.noDataMessage = null;
 287:         this.noDataMessageFont = new Font("SansSerif", Font.PLAIN, 12);
 288:         this.noDataMessagePaint = Color.black;
 289: 
 290:         this.drawingSupplier = new DefaultDrawingSupplier();
 291: 
 292:         this.listenerList = new EventListenerList();
 293: 
 294:     }
 295: 
 296:     /**
 297:      * Returns the dataset group for the plot (not currently used).
 298:      *
 299:      * @return The dataset group.
 300:      * 
 301:      * @see #setDatasetGroup(DatasetGroup)
 302:      */
 303:     public DatasetGroup getDatasetGroup() {
 304:         return this.datasetGroup;
 305:     }
 306: 
 307:     /**
 308:      * Sets the dataset group (not currently used).
 309:      *
 310:      * @param group  the dataset group (<code>null</code> permitted).
 311:      * 
 312:      * @see #getDatasetGroup()
 313:      */
 314:     protected void setDatasetGroup(DatasetGroup group) {
 315:         this.datasetGroup = group;
 316:     }
 317: 
 318:     /**
 319:      * Returns the string that is displayed when the dataset is empty or 
 320:      * <code>null</code>.
 321:      *
 322:      * @return The 'no data' message (<code>null</code> possible).
 323:      * 
 324:      * @see #setNoDataMessage(String)
 325:      * @see #getNoDataMessageFont()
 326:      * @see #getNoDataMessagePaint()
 327:      */
 328:     public String getNoDataMessage() {
 329:         return this.noDataMessage;
 330:     }
 331: 
 332:     /**
 333:      * Sets the message that is displayed when the dataset is empty or 
 334:      * <code>null</code>, and sends a {@link PlotChangeEvent} to all registered
 335:      * listeners.
 336:      *
 337:      * @param message  the message (<code>null</code> permitted).
 338:      * 
 339:      * @see #getNoDataMessage()
 340:      */
 341:     public void setNoDataMessage(String message) {
 342:         this.noDataMessage = message;
 343:         notifyListeners(new PlotChangeEvent(this));
 344:     }
 345: 
 346:     /**
 347:      * Returns the font used to display the 'no data' message.
 348:      *
 349:      * @return The font (never <code>null</code>).
 350:      * 
 351:      * @see #setNoDataMessageFont(Font)
 352:      * @see #getNoDataMessage()
 353:      */
 354:     public Font getNoDataMessageFont() {
 355:         return this.noDataMessageFont;
 356:     }
 357: 
 358:     /**
 359:      * Sets the font used to display the 'no data' message and sends a 
 360:      * {@link PlotChangeEvent} to all registered listeners.
 361:      *
 362:      * @param font  the font (<code>null</code> not permitted).
 363:      * 
 364:      * @see #getNoDataMessageFont()
 365:      */
 366:     public void setNoDataMessageFont(Font font) {
 367:         if (font == null) {
 368:             throw new IllegalArgumentException("Null 'font' argument.");
 369:         }
 370:         this.noDataMessageFont = font;
 371:         notifyListeners(new PlotChangeEvent(this));
 372:     }
 373: 
 374:     /**
 375:      * Returns the paint used to display the 'no data' message.
 376:      *
 377:      * @return The paint (never <code>null</code>).
 378:      * 
 379:      * @see #setNoDataMessagePaint(Paint)
 380:      * @see #getNoDataMessage()
 381:      */
 382:     public Paint getNoDataMessagePaint() {
 383:         return this.noDataMessagePaint;
 384:     }
 385: 
 386:     /**
 387:      * Sets the paint used to display the 'no data' message and sends a 
 388:      * {@link PlotChangeEvent} to all registered listeners.
 389:      *
 390:      * @param paint  the paint (<code>null</code> not permitted).
 391:      * 
 392:      * @see #getNoDataMessagePaint()
 393:      */
 394:     public void setNoDataMessagePaint(Paint paint) {
 395:         if (paint == null) {
 396:             throw new IllegalArgumentException("Null 'paint' argument.");
 397:         }
 398:         this.noDataMessagePaint = paint;
 399:         notifyListeners(new PlotChangeEvent(this));
 400:     }
 401: 
 402:     /**
 403:      * Returns a short string describing the plot type.
 404:      * <P>
 405:      * Note: this gets used in the chart property editing user interface,
 406:      * but there needs to be a better mechanism for identifying the plot type.
 407:      *
 408:      * @return A short string describing the plot type (never 
 409:      *     <code>null</code>).
 410:      */
 411:     public abstract String getPlotType();
 412: 
 413:     /**
 414:      * Returns the parent plot (or <code>null</code> if this plot is not part 
 415:      * of a combined plot).
 416:      *
 417:      * @return The parent plot.
 418:      * 
 419:      * @see #setParent(Plot)
 420:      * @see #getRootPlot()
 421:      */
 422:     public Plot getParent() {
 423:         return this.parent;
 424:     }
 425: 
 426:     /**
 427:      * Sets the parent plot.  This method is intended for internal use, you 
 428:      * shouldn't need to call it directly.
 429:      *
 430:      * @param parent  the parent plot (<code>null</code> permitted).
 431:      * 
 432:      * @see #getParent()
 433:      */
 434:     public void setParent(Plot parent) {
 435:         this.parent = parent;
 436:     }
 437: 
 438:     /**
 439:      * Returns the root plot.
 440:      *
 441:      * @return The root plot.
 442:      * 
 443:      * @see #getParent()
 444:      */
 445:     public Plot getRootPlot() {
 446: 
 447:         Plot p = getParent();
 448:         if (p == null) {
 449:             return this;
 450:         }
 451:         else {
 452:             return p.getRootPlot();
 453:         }
 454: 
 455:     }
 456: 
 457:     /**
 458:      * Returns <code>true</code> if this plot is part of a combined plot 
 459:      * structure (that is, {@link #getParent()} returns a non-<code>null</code>
 460:      * value), and <code>false</code> otherwise.
 461:      *
 462:      * @return <code>true</code> if this plot is part of a combined plot 
 463:      *         structure.
 464:      *         
 465:      * @see #getParent()
 466:      */
 467:     public boolean isSubplot() {
 468:         return (getParent() != null);
 469:     }
 470: 
 471:     /**
 472:      * Returns the insets for the plot area.
 473:      *
 474:      * @return The insets (never <code>null</code>).
 475:      * 
 476:      * @see #setInsets(RectangleInsets)
 477:      */
 478:     public RectangleInsets getInsets() {
 479:         return this.insets;
 480:     }
 481: 
 482:     /**
 483:      * Sets the insets for the plot and sends a {@link PlotChangeEvent} to 
 484:      * all registered listeners.
 485:      *
 486:      * @param insets  the new insets (<code>null</code> not permitted).
 487:      * 
 488:      * @see #getInsets()
 489:      * @see #setInsets(RectangleInsets, boolean)
 490:      */
 491:     public void setInsets(RectangleInsets insets) {
 492:         setInsets(insets, true);
 493:     }
 494: 
 495:     /**
 496:      * Sets the insets for the plot and, if requested,  and sends a 
 497:      * {@link PlotChangeEvent} to all registered listeners.
 498:      *
 499:      * @param insets  the new insets (<code>null</code> not permitted).
 500:      * @param notify  a flag that controls whether the registered listeners are
 501:      *                notified.
 502:      *                
 503:      * @see #getInsets()
 504:      * @see #setInsets(RectangleInsets)
 505:      */
 506:     public void setInsets(RectangleInsets insets, boolean notify) {
 507:         if (insets == null) {
 508:             throw new IllegalArgumentException("Null 'insets' argument.");
 509:         }
 510:         if (!this.insets.equals(insets)) {
 511:             this.insets = insets;
 512:             if (notify) {
 513:                 notifyListeners(new PlotChangeEvent(this));
 514:             }
 515:         }
 516: 
 517:     }
 518: 
 519:     /**
 520:      * Returns the background color of the plot area.
 521:      *
 522:      * @return The paint (possibly <code>null</code>).
 523:      * 
 524:      * @see #setBackgroundPaint(Paint)
 525:      */
 526:     public Paint getBackgroundPaint() {
 527:         return this.backgroundPaint;
 528:     }
 529: 
 530:     /**
 531:      * Sets the background color of the plot area and sends a 
 532:      * {@link PlotChangeEvent} to all registered listeners.
 533:      *
 534:      * @param paint  the paint (<code>null</code> permitted).
 535:      * 
 536:      * @see #getBackgroundPaint()
 537:      */
 538:     public void setBackgroundPaint(Paint paint) {
 539: 
 540:         if (paint == null) {
 541:             if (this.backgroundPaint != null) {
 542:                 this.backgroundPaint = null;
 543:                 notifyListeners(new PlotChangeEvent(this));
 544:             }
 545:         }
 546:         else {
 547:             if (this.backgroundPaint != null) {
 548:                 if (this.backgroundPaint.equals(paint)) {
 549:                     return;  // nothing to do
 550:                 }
 551:             }
 552:             this.backgroundPaint = paint;
 553:             notifyListeners(new PlotChangeEvent(this));
 554:         }
 555: 
 556:     }
 557: 
 558:     /**
 559:      * Returns the alpha transparency of the plot area background.
 560:      *
 561:      * @return The alpha transparency.
 562:      * 
 563:      * @see #setBackgroundAlpha(float)
 564:      */
 565:     public float getBackgroundAlpha() {
 566:         return this.backgroundAlpha;
 567:     }
 568: 
 569:     /**
 570:      * Sets the alpha transparency of the plot area background, and notifies
 571:      * registered listeners that the plot has been modified.
 572:      *
 573:      * @param alpha the new alpha value (in the range 0.0f to 1.0f).
 574:      * 
 575:      * @see #getBackgroundAlpha()
 576:      */
 577:     public void setBackgroundAlpha(float alpha) {
 578:         if (this.backgroundAlpha != alpha) {
 579:             this.backgroundAlpha = alpha;
 580:             notifyListeners(new PlotChangeEvent(this));
 581:         }
 582:     }
 583: 
 584:     /**
 585:      * Returns the drawing supplier for the plot.
 586:      *
 587:      * @return The drawing supplier (possibly <code>null</code>).
 588:      * 
 589:      * @see #setDrawingSupplier(DrawingSupplier)
 590:      */
 591:     public DrawingSupplier getDrawingSupplier() {
 592:         DrawingSupplier result = null;
 593:         Plot p = getParent();
 594:         if (p != null) {
 595:             result = p.getDrawingSupplier();
 596:         }
 597:         else {
 598:             result = this.drawingSupplier;
 599:         }
 600:         return result;
 601:     }
 602: 
 603:     /**
 604:      * Sets the drawing supplier for the plot.  The drawing supplier is 
 605:      * responsible for supplying a limitless (possibly repeating) sequence of 
 606:      * <code>Paint</code>, <code>Stroke</code> and <code>Shape</code> objects 
 607:      * that the plot's renderer(s) can use to populate its (their) tables.
 608:      *
 609:      * @param supplier  the new supplier.
 610:      * 
 611:      * @see #getDrawingSupplier()
 612:      */
 613:     public void setDrawingSupplier(DrawingSupplier supplier) {
 614:         this.drawingSupplier = supplier;
 615:         notifyListeners(new PlotChangeEvent(this));
 616:     }
 617: 
 618:     /**
 619:      * Returns the background image that is used to fill the plot's background 
 620:      * area.
 621:      *
 622:      * @return The image (possibly <code>null</code>).
 623:      * 
 624:      * @see #setBackgroundImage(Image)
 625:      */
 626:     public Image getBackgroundImage() {
 627:         return this.backgroundImage;
 628:     }
 629: 
 630:     /**
 631:      * Sets the background image for the plot and sends a 
 632:      * {@link PlotChangeEvent} to all registered listeners.
 633:      *
 634:      * @param image  the image (<code>null</code> permitted).
 635:      * 
 636:      * @see #getBackgroundImage()
 637:      */
 638:     public void setBackgroundImage(Image image) {
 639:         this.backgroundImage = image;
 640:         notifyListeners(new PlotChangeEvent(this));
 641:     }
 642: 
 643:     /**
 644:      * Returns the background image alignment. Alignment constants are defined 
 645:      * in the <code>org.jfree.ui.Align</code> class in the JCommon class 
 646:      * library.
 647:      *
 648:      * @return The alignment.
 649:      * 
 650:      * @see #setBackgroundImageAlignment(int)
 651:      */
 652:     public int getBackgroundImageAlignment() {
 653:         return this.backgroundImageAlignment;
 654:     }
 655: 
 656:     /**
 657:      * Sets the alignment for the background image and sends a 
 658:      * {@link PlotChangeEvent} to all registered listeners.  Alignment options 
 659:      * are defined by the {@link org.jfree.ui.Align} class in the JCommon 
 660:      * class library.
 661:      *
 662:      * @param alignment  the alignment.
 663:      * 
 664:      * @see #getBackgroundImageAlignment()
 665:      */
 666:     public void setBackgroundImageAlignment(int alignment) {
 667:         if (this.backgroundImageAlignment != alignment) {
 668:             this.backgroundImageAlignment = alignment;
 669:             notifyListeners(new PlotChangeEvent(this));
 670:         }
 671:     }
 672: 
 673:     /**
 674:      * Returns the alpha transparency used to draw the background image.  This
 675:      * is a value in the range 0.0f to 1.0f, where 0.0f is fully transparent
 676:      * and 1.0f is fully opaque.
 677:      * 
 678:      * @return The alpha transparency.
 679:      * 
 680:      * @see #setBackgroundImageAlpha(float)
 681:      */
 682:     public float getBackgroundImageAlpha() {
 683:         return this.backgroundImageAlpha;
 684:     }
 685:     
 686:     /**
 687:      * Sets the alpha transparency used when drawing the background image.
 688:      * 
 689:      * @param alpha  the alpha transparency (in the range 0.0f to 1.0f, where
 690:      *     0.0f is fully transparent, and 1.0f is fully opaque).
 691:      *     
 692:      * @throws IllegalArgumentException if <code>alpha</code> is not within
 693:      *     the specified range.
 694:      *     
 695:      * @see #getBackgroundImageAlpha()
 696:      */
 697:     public void setBackgroundImageAlpha(float alpha) {
 698:         if (alpha < 0.0f || alpha > 1.0f)
 699:             throw new IllegalArgumentException(
 700:                     "The 'alpha' value must be in the range 0.0f to 1.0f.");
 701:         if (this.backgroundImageAlpha != alpha) {
 702:             this.backgroundImageAlpha = alpha;
 703:             this.notifyListeners(new PlotChangeEvent(this));
 704:         }
 705:     }
 706:     
 707:     /**
 708:      * Returns the stroke used to outline the plot area.
 709:      *
 710:      * @return The stroke (possibly <code>null</code>).
 711:      * 
 712:      * @see #setOutlineStroke(Stroke)
 713:      */
 714:     public Stroke getOutlineStroke() {
 715:         return this.outlineStroke;
 716:     }
 717: 
 718:     /**
 719:      * Sets the stroke used to outline the plot area and sends a 
 720:      * {@link PlotChangeEvent} to all registered listeners. If you set this 
 721:      * attribute to <code>null</code>, no outline will be drawn.
 722:      *
 723:      * @param stroke  the stroke (<code>null</code> permitted).
 724:      * 
 725:      * @see #getOutlineStroke()
 726:      */
 727:     public void setOutlineStroke(Stroke stroke) {
 728:         if (stroke == null) {
 729:             if (this.outlineStroke != null) {
 730:                 this.outlineStroke = null;
 731:                 notifyListeners(new PlotChangeEvent(this));
 732:             }
 733:         }
 734:         else {
 735:             if (this.outlineStroke != null) {
 736:                 if (this.outlineStroke.equals(stroke)) {
 737:                     return;  // nothing to do
 738:                 }
 739:             }
 740:             this.outlineStroke = stroke;
 741:             notifyListeners(new PlotChangeEvent(this));
 742:         }
 743:     }
 744: 
 745:     /**
 746:      * Returns the color used to draw the outline of the plot area.
 747:      *
 748:      * @return The color (possibly <code>null<code>).
 749:      * 
 750:      * @see #setOutlinePaint(Paint)
 751:      */
 752:     public Paint getOutlinePaint() {
 753:         return this.outlinePaint;
 754:     }
 755: 
 756:     /**
 757:      * Sets the paint used to draw the outline of the plot area and sends a 
 758:      * {@link PlotChangeEvent} to all registered listeners.  If you set this 
 759:      * attribute to <code>null</code>, no outline will be drawn.
 760:      *
 761:      * @param paint  the paint (<code>null</code> permitted).
 762:      * 
 763:      * @see #getOutlinePaint()
 764:      */
 765:     public void setOutlinePaint(Paint paint) {
 766:         if (paint == null) {
 767:             if (this.outlinePaint != null) {
 768:                 this.outlinePaint = null;
 769:                 notifyListeners(new PlotChangeEvent(this));
 770:             }
 771:         }
 772:         else {
 773:             if (this.outlinePaint != null) {
 774:                 if (this.outlinePaint.equals(paint)) {
 775:                     return;  // nothing to do
 776:                 }
 777:             }
 778:             this.outlinePaint = paint;
 779:             notifyListeners(new PlotChangeEvent(this));
 780:         }
 781:     }
 782: 
 783:     /**
 784:      * Returns the alpha-transparency for the plot foreground.
 785:      *
 786:      * @return The alpha-transparency.
 787:      * 
 788:      * @see #setForegroundAlpha(float)
 789:      */
 790:     public float getForegroundAlpha() {
 791:         return this.foregroundAlpha;
 792:     }
 793: 
 794:     /**
 795:      * Sets the alpha-transparency for the plot and sends a 
 796:      * {@link PlotChangeEvent} to all registered listeners.
 797:      *
 798:      * @param alpha  the new alpha transparency.
 799:      * 
 800:      * @see #getForegroundAlpha()
 801:      */
 802:     public void setForegroundAlpha(float alpha) {
 803:         if (this.foregroundAlpha != alpha) {
 804:             this.foregroundAlpha = alpha;
 805:             notifyListeners(new PlotChangeEvent(this));
 806:         }
 807:     }
 808: 
 809:     /**
 810:      * Returns the legend items for the plot.  By default, this method returns 
 811:      * <code>null</code>.  Subclasses should override to return a 
 812:      * {@link LegendItemCollection}.
 813:      *
 814:      * @return The legend items for the plot (possibly <code>null</code>).
 815:      */
 816:     public LegendItemCollection getLegendItems() {
 817:         return null;
 818:     }
 819: 
 820:     /**
 821:      * Registers an object for notification of changes to the plot.
 822:      *
 823:      * @param listener  the object to be registered.
 824:      * 
 825:      * @see #removeChangeListener(PlotChangeListener)
 826:      */
 827:     public void addChangeListener(PlotChangeListener listener) {
 828:         this.listenerList.add(PlotChangeListener.class, listener);
 829:     }
 830: 
 831:     /**
 832:      * Unregisters an object for notification of changes to the plot.
 833:      *
 834:      * @param listener  the object to be unregistered.
 835:      * 
 836:      * @see #addChangeListener(PlotChangeListener)
 837:      */
 838:     public void removeChangeListener(PlotChangeListener listener) {
 839:         this.listenerList.remove(PlotChangeListener.class, listener);
 840:     }
 841: 
 842:     /**
 843:      * Notifies all registered listeners that the plot has been modified.
 844:      *
 845:      * @param event  information about the change event.
 846:      */
 847:     public void notifyListeners(PlotChangeEvent event) {
 848:         Object[] listeners = this.listenerList.getListenerList();
 849:         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 850:             if (listeners[i] == PlotChangeListener.class) {
 851:                 ((PlotChangeListener) listeners[i + 1]).plotChanged(event);
 852:             }
 853:         }
 854:     }
 855: 
 856:     /**
 857:      * Draws the plot within the specified area.  The anchor is a point on the
 858:      * chart that is specified externally (for instance, it may be the last
 859:      * point of the last mouse click performed by the user) - plots can use or
 860:      * ignore this value as they see fit. 
 861:      * <br><br>
 862:      * Subclasses need to provide an implementation of this method, obviously.
 863:      * 
 864:      * @param g2  the graphics device.
 865:      * @param area  the plot area.
 866:      * @param anchor  the anchor point (<code>null</code> permitted).
 867:      * @param parentState  the parent state (if any).
 868:      * @param info  carries back plot rendering info.
 869:      */
 870:     public abstract void draw(Graphics2D g2,
 871:                               Rectangle2D area,
 872:                               Point2D anchor,
 873:                               PlotState parentState,
 874:                               PlotRenderingInfo info);
 875:                               
 876:     /**
 877:      * Draws the plot background (the background color and/or image).
 878:      * <P>
 879:      * This method will be called during the chart drawing process and is 
 880:      * declared public so that it can be accessed by the renderers used by 
 881:      * certain subclasses.  You shouldn't need to call this method directly.
 882:      *
 883:      * @param g2  the graphics device.
 884:      * @param area  the area within which the plot should be drawn.
 885:      */
 886:     public void drawBackground(Graphics2D g2, Rectangle2D area) {
 887:         fillBackground(g2, area);
 888:         drawBackgroundImage(g2, area);
 889:     }
 890: 
 891:     /**
 892:      * Fills the specified area with the background paint.
 893:      * 
 894:      * @param g2  the graphics device.
 895:      * @param area  the area.
 896:      * 
 897:      * @see #getBackgroundPaint()
 898:      * @see #getBackgroundAlpha()
 899:      */
 900:     protected void fillBackground(Graphics2D g2, Rectangle2D area) {
 901:         if (this.backgroundPaint != null) {
 902:             Composite originalComposite = g2.getComposite();
 903:             g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
 904:                     this.backgroundAlpha));
 905:             g2.setPaint(this.backgroundPaint);
 906:             g2.fill(area);
 907:             g2.setComposite(originalComposite);
 908:         }
 909:     }
 910:     
 911:     /**
 912:      * Draws the background image (if there is one) aligned within the 
 913:      * specified area.
 914:      * 
 915:      * @param g2  the graphics device.
 916:      * @param area  the area.
 917:      * 
 918:      * @see #getBackgroundImage()
 919:      * @see #getBackgroundImageAlignment()
 920:      * @see #getBackgroundImageAlpha()
 921:      */
 922:     protected void drawBackgroundImage(Graphics2D g2, Rectangle2D area) {
 923:         if (this.backgroundImage != null) {
 924:             Composite originalComposite = g2.getComposite();
 925:             g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 
 926:                     this.backgroundImageAlpha));
 927:             Rectangle2D dest = new Rectangle2D.Double(0.0, 0.0,
 928:                     this.backgroundImage.getWidth(null), 
 929:                     this.backgroundImage.getHeight(null));
 930:             Align.align(dest, area, this.backgroundImageAlignment);
 931:             g2.drawImage(this.backgroundImage, (int) dest.getX(), 
 932:                     (int) dest.getY(), (int) dest.getWidth() + 1, 
 933:                     (int) dest.getHeight() + 1, null);
 934:             g2.setComposite(originalComposite);
 935:         }
 936:     }
 937:     
 938:     /**
 939:      * Draws the plot outline.  This method will be called during the chart 
 940:      * drawing process and is declared public so that it can be accessed by the
 941:      * renderers used by certain subclasses. You shouldn't need to call this 
 942:      * method directly.
 943:      * 
 944:      * @param g2  the graphics device.
 945:      * @param area  the area within which the plot should be drawn.
 946:      */
 947:     public void drawOutline(Graphics2D g2, Rectangle2D area) {
 948:         if ((this.outlineStroke != null) && (this.outlinePaint != null)) {
 949:             g2.setStroke(this.outlineStroke);
 950:             g2.setPaint(this.outlinePaint);
 951:             g2.draw(area);
 952:         }
 953:     }
 954: 
 955:     /**
 956:      * Draws a message to state that there is no data to plot.
 957:      *
 958:      * @param g2  the graphics device.
 959:      * @param area  the area within which the plot should be drawn.
 960:      */
 961:     protected void drawNoDataMessage(Graphics2D g2, Rectangle2D area) {
 962:         Shape savedClip = g2.getClip();
 963:         g2.clip(area);
 964:         String message = this.noDataMessage;
 965:         if (message != null) {
 966:             g2.setFont(this.noDataMessageFont);
 967:             g2.setPaint(this.noDataMessagePaint);
 968:             TextBlock block = TextUtilities.createTextBlock(
 969:                     this.noDataMessage, this.noDataMessageFont, 
 970:                     this.noDataMessagePaint, 0.9f * (float) area.getWidth(), 
 971:                     new G2TextMeasurer(g2));
 972:             block.draw(g2, (float) area.getCenterX(), (float) area.getCenterY(), 
 973:                     TextBlockAnchor.CENTER);
 974:         }
 975:         g2.setClip(savedClip);
 976:     }
 977: 
 978:     /**
 979:      * Handles a 'click' on the plot.  Since the plot does not maintain any
 980:      * information about where it has been drawn, the plot rendering info is 
 981:      * supplied as an argument.
 982:      *
 983:      * @param x  the x coordinate (in Java2D space).
 984:      * @param y  the y coordinate (in Java2D space).
 985:      * @param info  an object containing information about the dimensions of 
 986:      *              the plot.
 987:      */
 988:     public void handleClick(int x, int y, PlotRenderingInfo info) {
 989:         // provides a 'no action' default
 990:     }
 991: 
 992:     /**
 993:      * Performs a zoom on the plot.  Subclasses should override if zooming is 
 994:      * appropriate for the type of plot.
 995:      *
 996:      * @param percent  the zoom percentage.
 997:      */
 998:     public void zoom(double percent) {
 999:         // do nothing by default.
1000:     }
1001: 
1002:     /**
1003:      * Receives notification of a change to one of the plot's axes.
1004:      *
1005:      * @param event  information about the event (not used here).
1006:      */
1007:     public void axisChanged(AxisChangeEvent event) {
1008:         notifyListeners(new PlotChangeEvent(this));
1009:     }
1010: 
1011:     /**
1012:      * Receives notification of a change to the plot's dataset.
1013:      * <P>
1014:      * The plot reacts by passing on a plot change event to all registered 
1015:      * listeners.
1016:      *
1017:      * @param event  information about the event (not used here).
1018:      */
1019:     public void datasetChanged(DatasetChangeEvent event) {
1020:         PlotChangeEvent newEvent = new PlotChangeEvent(this);
1021:         newEvent.setType(ChartChangeEventType.DATASET_UPDATED);
1022:         notifyListeners(newEvent);
1023:     }
1024:     
1025:     /**
1026:      * Receives notification of a change to a marker that is assigned to the
1027:      * plot.
1028:      * 
1029:      * @param event  the event.
1030:      * 
1031:      * @since 1.0.3
1032:      */
1033:     public void markerChanged(MarkerChangeEvent event) {
1034:         notifyListeners(new PlotChangeEvent(this));
1035:     }
1036: 
1037:     /**
1038:      * Adjusts the supplied x-value.
1039:      *
1040:      * @param x  the x-value.
1041:      * @param w1  width 1.
1042:      * @param w2  width 2.
1043:      * @param edge  the edge (left or right).
1044:      *
1045:      * @return The adjusted x-value.
1046:      */
1047:     protected double getRectX(double x, double w1, double w2, 
1048:                               RectangleEdge edge) {
1049: 
1050:         double result = x;
1051:         if (edge == RectangleEdge.LEFT) {
1052:             result = result + w1;
1053:         }
1054:         else if (edge == RectangleEdge.RIGHT) {
1055:             result = result + w2;
1056:         }
1057:         return result;
1058: 
1059:     }
1060: 
1061:     /**
1062:      * Adjusts the supplied y-value.
1063:      *
1064:      * @param y  the x-value.
1065:      * @param h1  height 1.
1066:      * @param h2  height 2.
1067:      * @param edge  the edge (top or bottom).
1068:      *
1069:      * @return The adjusted y-value.
1070:      */
1071:     protected double getRectY(double y, double h1, double h2, 
1072:                               RectangleEdge edge) {
1073: 
1074:         double result = y;
1075:         if (edge == RectangleEdge.TOP) {
1076:             result = result + h1;
1077:         }
1078:         else if (edge == RectangleEdge.BOTTOM) {
1079:             result = result + h2;
1080:         }
1081:         return result;
1082: 
1083:     }
1084: 
1085:     /**
1086:      * Tests this plot for equality with another object.
1087:      *
1088:      * @param obj  the object (<code>null</code> permitted).
1089:      *
1090:      * @return <code>true</code> or <code>false</code>.
1091:      */
1092:     public boolean equals(Object obj) {
1093:         if (obj == this) {
1094:             return true;
1095:         }
1096:         if (!(obj instanceof Plot)) {
1097:             return false;
1098:         }
1099:         Plot that = (Plot) obj;
1100:         if (!ObjectUtilities.equal(this.noDataMessage, that.noDataMessage)) {
1101:             return false;
1102:         }
1103:         if (!ObjectUtilities.equal(
1104:             this.noDataMessageFont, that.noDataMessageFont
1105:         )) {
1106:             return false;
1107:         }
1108:         if (!PaintUtilities.equal(this.noDataMessagePaint, 
1109:                 that.noDataMessagePaint)) {
1110:             return false;
1111:         }
1112:         if (!ObjectUtilities.equal(this.insets, that.insets)) {
1113:             return false;
1114:         }
1115:         if (!ObjectUtilities.equal(this.outlineStroke, that.outlineStroke)) {
1116:             return false;
1117:         }
1118:         if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) {
1119:             return false;
1120:         }
1121:         if (!PaintUtilities.equal(this.backgroundPaint, that.backgroundPaint)) {
1122:             return false;
1123:         }
1124:         if (!ObjectUtilities.equal(this.backgroundImage, 
1125:                 that.backgroundImage)) {
1126:             return false;
1127:         }
1128:         if (this.backgroundImageAlignment != that.backgroundImageAlignment) {
1129:             return false;
1130:         }
1131:         if (this.backgroundImageAlpha != that.backgroundImageAlpha) {
1132:             return false;
1133:         }
1134:         if (this.foregroundAlpha != that.foregroundAlpha) {
1135:             return false;
1136:         }
1137:         if (this.backgroundAlpha != that.backgroundAlpha) {
1138:             return false;
1139:         }
1140:         if (!this.drawingSupplier.equals(that.drawingSupplier)) {
1141:             return false;   
1142:         }
1143:         return true;
1144:     }
1145: 
1146:     /**
1147:      * Creates a clone of the plot.
1148:      *
1149:      * @return A clone.
1150:      *
1151:      * @throws CloneNotSupportedException if some component of the plot does not
1152:      *         support cloning.
1153:      */
1154:     public Object clone() throws CloneNotSupportedException {
1155: 
1156:         Plot clone = (Plot) super.clone();
1157:         // private Plot parent <-- don't clone the parent plot, but take care 
1158:         // childs in combined plots instead
1159:         if (this.datasetGroup != null) {
1160:             clone.datasetGroup 
1161:                 = (DatasetGroup) ObjectUtilities.clone(this.datasetGroup);
1162:         }
1163:         clone.drawingSupplier 
1164:             = (DrawingSupplier) ObjectUtilities.clone(this.drawingSupplier);
1165:         clone.listenerList = new EventListenerList();
1166:         return clone;
1167: 
1168:     }
1169: 
1170:     /**
1171:      * Provides serialization support.
1172:      *
1173:      * @param stream  the output stream.
1174:      *
1175:      * @throws IOException  if there is an I/O error.
1176:      */
1177:     private void writeObject(ObjectOutputStream stream) throws IOException {
1178:         stream.defaultWriteObject();
1179:         SerialUtilities.writePaint(this.noDataMessagePaint, stream);
1180:         SerialUtilities.writeStroke(this.outlineStroke, stream);
1181:         SerialUtilities.writePaint(this.outlinePaint, stream);
1182:         // backgroundImage
1183:         SerialUtilities.writePaint(this.backgroundPaint, stream);
1184:     }
1185: 
1186:     /**
1187:      * Provides serialization support.
1188:      *
1189:      * @param stream  the input stream.
1190:      *
1191:      * @throws IOException  if there is an I/O error.
1192:      * @throws ClassNotFoundException  if there is a classpath problem.
1193:      */
1194:     private void readObject(ObjectInputStream stream) 
1195:         throws IOException, ClassNotFoundException {
1196:         stream.defaultReadObject();
1197:         this.noDataMessagePaint = SerialUtilities.readPaint(stream);
1198:         this.outlineStroke = SerialUtilities.readStroke(stream);
1199:         this.outlinePaint = SerialUtilities.readPaint(stream);
1200:         // backgroundImage
1201:         this.backgroundPaint = SerialUtilities.readPaint(stream);
1202: 
1203:         this.listenerList = new EventListenerList();
1204: 
1205:     }
1206: 
1207:     /**
1208:      * Resolves a domain axis location for a given plot orientation.
1209:      *
1210:      * @param location  the location (<code>null</code> not permitted).
1211:      * @param orientation  the orientation (<code>null</code> not permitted).
1212:      *
1213:      * @return The edge (never <code>null</code>).
1214:      */
1215:     public static RectangleEdge resolveDomainAxisLocation(
1216:             AxisLocation location, PlotOrientation orientation) {
1217:         
1218:         if (location == null) {
1219:             throw new IllegalArgumentException("Null 'location' argument.");   
1220:         }
1221:         if (orientation == null) {
1222:             throw new IllegalArgumentException("Null 'orientation' argument.");
1223:         }
1224: 
1225:         RectangleEdge result = null;
1226:         
1227:         if (location == AxisLocation.TOP_OR_RIGHT) {
1228:             if (orientation == PlotOrientation.HORIZONTAL) {
1229:                 result = RectangleEdge.RIGHT;
1230:             }
1231:             else if (orientation == PlotOrientation.VERTICAL) {
1232:                 result = RectangleEdge.TOP;
1233:             }
1234:         }
1235:         else if (location == AxisLocation.TOP_OR_LEFT) {
1236:             if (orientation == PlotOrientation.HORIZONTAL) {
1237:                 result = RectangleEdge.LEFT;
1238:             }
1239:             else if (orientation == PlotOrientation.VERTICAL) {
1240:                 result = RectangleEdge.TOP;
1241:             }
1242:         }
1243:         else if (location == AxisLocation.BOTTOM_OR_RIGHT) {
1244:             if (orientation == PlotOrientation.HORIZONTAL) {
1245:                 result = RectangleEdge.RIGHT;
1246:             }
1247:             else if (orientation == PlotOrientation.VERTICAL) {
1248:                 result = RectangleEdge.BOTTOM;
1249:             }
1250:         }
1251:         else if (location == AxisLocation.BOTTOM_OR_LEFT) {
1252:             if (orientation == PlotOrientation.HORIZONTAL) {
1253:                 result = RectangleEdge.LEFT;
1254:             }
1255:             else if (orientation == PlotOrientation.VERTICAL) {
1256:                 result = RectangleEdge.BOTTOM;
1257:             }
1258:         }
1259:         // the above should cover all the options...
1260:         if (result == null) {
1261:             throw new IllegalStateException("resolveDomainAxisLocation()");
1262:         }
1263:         return result;
1264:         
1265:     }
1266: 
1267:     /**
1268:      * Resolves a range axis location for a given plot orientation.
1269:      *
1270:      * @param location  the location (<code>null</code> not permitted).
1271:      * @param orientation  the orientation (<code>null</code> not permitted).
1272:      *
1273:      * @return The edge (never <code>null</code>).
1274:      */
1275:     public static RectangleEdge resolveRangeAxisLocation(
1276:             AxisLocation location, PlotOrientation orientation) {
1277: 
1278:         if (location == null) {
1279:             throw new IllegalArgumentException("Null 'location' argument.");   
1280:         }
1281:         if (orientation == null) {
1282:             throw new IllegalArgumentException("Null 'orientation' argument.");
1283:         }
1284: 
1285:         RectangleEdge result = null;
1286:         
1287:         if (location == AxisLocation.TOP_OR_RIGHT) {
1288:             if (orientation == PlotOrientation.HORIZONTAL) {
1289:                 result = RectangleEdge.TOP;
1290:             }
1291:             else if (orientation == PlotOrientation.VERTICAL) {
1292:                 result = RectangleEdge.RIGHT;
1293:             }
1294:         }
1295:         else if (location == AxisLocation.TOP_OR_LEFT) {
1296:             if (orientation == PlotOrientation.HORIZONTAL) {
1297:                 result = RectangleEdge.TOP;
1298:             }
1299:             else if (orientation == PlotOrientation.VERTICAL) {
1300:                 result = RectangleEdge.LEFT;
1301:             }
1302:         }
1303:         else if (location == AxisLocation.BOTTOM_OR_RIGHT) {
1304:             if (orientation == PlotOrientation.HORIZONTAL) {
1305:                 result = RectangleEdge.BOTTOM;
1306:             }
1307:             else if (orientation == PlotOrientation.VERTICAL) {
1308:                 result = RectangleEdge.RIGHT;
1309:             }
1310:         }
1311:         else if (location == AxisLocation.BOTTOM_OR_LEFT) {
1312:             if (orientation == PlotOrientation.HORIZONTAL) {
1313:                 result = RectangleEdge.BOTTOM;
1314:             }
1315:             else if (orientation == PlotOrientation.VERTICAL) {
1316:                 result = RectangleEdge.LEFT;
1317:             }
1318:         }
1319: 
1320:         // the above should cover all the options...
1321:         if (result == null) {
1322:             throw new IllegalStateException("resolveRangeAxisLocation()");
1323:         }
1324:         return result;
1325:         
1326:     }
1327: 
1328: }