0001: /* ===========================================================
0002: * JFreeChart : a free chart library for the Java(tm) platform
0003: * ===========================================================
0004: *
0005: * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
0006: *
0007: * Project Info: http://www.jfree.org/jfreechart/index.html
0008: *
0009: * This library is free software; you can redistribute it and/or modify it
0010: * under the terms of the GNU Lesser General Public License as published by
0011: * the Free Software Foundation; either version 2.1 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * This library is distributed in the hope that it will be useful, but
0015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
0016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
0017: * License for more details.
0018: *
0019: * You should have received a copy of the GNU Lesser General Public
0020: * License along with this library; if not, write to the Free Software
0021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
0022: * USA.
0023: *
0024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
0025: * in the United States and other countries.]
0026: *
0027: * ---------
0028: * Plot.java
0029: * ---------
0030: * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
0031: *
0032: * Original Author: David Gilbert (for Object Refinery Limited);
0033: * Contributor(s): Sylvain Vieujot;
0034: * Jeremy Bowman;
0035: * Andreas Schneider;
0036: * Gideon Krause;
0037: * Nicolas Brodu;
0038: * Michal Krause;
0039: *
0040: * $Id: Plot.java,v 1.18.2.9 2007/06/07 12:49:36 mungady Exp $
0041: *
0042: * Changes (from 21-Jun-2001)
0043: * --------------------------
0044: * 21-Jun-2001 : Removed redundant JFreeChart parameter from constructors (DG);
0045: * 18-Sep-2001 : Updated header info and fixed DOS encoding problem (DG);
0046: * 19-Oct-2001 : Moved series paint and stroke methods from JFreeChart
0047: * class (DG);
0048: * 23-Oct-2001 : Created renderer for LinePlot class (DG);
0049: * 07-Nov-2001 : Changed type names for ChartChangeEvent (DG);
0050: * Tidied up some Javadoc comments (DG);
0051: * 13-Nov-2001 : Changes to allow for null axes on plots such as PiePlot (DG);
0052: * Added plot/axis compatibility checks (DG);
0053: * 12-Dec-2001 : Changed constructors to protected, and removed unnecessary
0054: * 'throws' clauses (DG);
0055: * 13-Dec-2001 : Added tooltips (DG);
0056: * 22-Jan-2002 : Added handleClick() method, as part of implementation for
0057: * crosshairs (DG);
0058: * Moved tooltips reference into ChartInfo class (DG);
0059: * 23-Jan-2002 : Added test for null axes in chartChanged() method, thanks
0060: * to Barry Evans for the bug report (number 506979 on
0061: * SourceForge) (DG);
0062: * Added a zoom() method (DG);
0063: * 05-Feb-2002 : Updated setBackgroundPaint(), setOutlineStroke() and
0064: * setOutlinePaint() to better handle null values, as suggested
0065: * by Sylvain Vieujot (DG);
0066: * 06-Feb-2002 : Added background image, plus alpha transparency for background
0067: * and foreground (DG);
0068: * 06-Mar-2002 : Added AxisConstants interface (DG);
0069: * 26-Mar-2002 : Changed zoom method from empty to abstract (DG);
0070: * 23-Apr-2002 : Moved dataset from JFreeChart class (DG);
0071: * 11-May-2002 : Added ShapeFactory interface for getShape() methods,
0072: * contributed by Jeremy Bowman (DG);
0073: * 28-May-2002 : Fixed bug in setSeriesPaint(int, Paint) for subplots (AS);
0074: * 25-Jun-2002 : Removed redundant imports (DG);
0075: * 30-Jul-2002 : Added 'no data' message for charts with null or empty
0076: * datasets (DG);
0077: * 21-Aug-2002 : Added code to extend series array if necessary (refer to
0078: * SourceForge bug id 594547 for details) (DG);
0079: * 17-Sep-2002 : Fixed bug in getSeriesOutlineStroke() method, reported by
0080: * Andreas Schroeder (DG);
0081: * 23-Sep-2002 : Added getLegendItems() abstract method (DG);
0082: * 24-Sep-2002 : Removed firstSeriesIndex, subplots now use their own paint
0083: * settings, there is a new mechanism for the legend to collect
0084: * the legend items (DG);
0085: * 27-Sep-2002 : Added dataset group (DG);
0086: * 14-Oct-2002 : Moved listener storage into EventListenerList. Changed some
0087: * abstract methods to empty implementations (DG);
0088: * 28-Oct-2002 : Added a getBackgroundImage() method (DG);
0089: * 21-Nov-2002 : Added a plot index for identifying subplots in combined and
0090: * overlaid charts (DG);
0091: * 22-Nov-2002 : Changed all attributes from 'protected' to 'private'. Added
0092: * dataAreaRatio attribute from David M O'Donnell's code (DG);
0093: * 09-Jan-2003 : Integrated fix for plot border contributed by Gideon
0094: * Krause (DG);
0095: * 17-Jan-2003 : Moved to com.jrefinery.chart.plot (DG);
0096: * 23-Jan-2003 : Removed one constructor (DG);
0097: * 26-Mar-2003 : Implemented Serializable (DG);
0098: * 14-Jul-2003 : Moved the dataset and secondaryDataset attributes to the
0099: * CategoryPlot and XYPlot classes (DG);
0100: * 21-Jul-2003 : Moved DrawingSupplier from CategoryPlot and XYPlot up to this
0101: * class (DG);
0102: * 20-Aug-2003 : Implemented Cloneable (DG);
0103: * 11-Sep-2003 : Listeners and clone (NB);
0104: * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
0105: * 03-Dec-2003 : Modified draw method to accept anchor (DG);
0106: * 12-Mar-2004 : Fixed clipping bug in drawNoDataMessage() method (DG);
0107: * 07-Apr-2004 : Modified string bounds calculation (DG);
0108: * 04-Nov-2004 : Added default shapes for legend items (DG);
0109: * 25-Nov-2004 : Some changes to the clone() method implementation (DG);
0110: * 23-Feb-2005 : Implemented new LegendItemSource interface (and also
0111: * PublicCloneable) (DG);
0112: * 21-Apr-2005 : Replaced Insets with RectangleInsets (DG);
0113: * 05-May-2005 : Removed unused draw() method (DG);
0114: * 06-Jun-2005 : Fixed bugs in equals() method (DG);
0115: * 01-Sep-2005 : Moved dataAreaRatio from here to ContourPlot (DG);
0116: * ------------- JFREECHART 1.0.x ---------------------------------------------
0117: * 30-Jun-2006 : Added background image alpha - see bug report 1514904 (DG);
0118: * 05-Sep-2006 : Implemented the MarkerChangeListener interface (DG);
0119: * 11-Jan-2007 : Added some argument checks, event notifications, and many
0120: * API doc updates (DG);
0121: * 03-Apr-2007 : Made drawBackgroundImage() public (DG);
0122: * 07-Jun-2007 : Added new fillBackground() method to handle GradientPaint
0123: * taking into account orientation (DG);
0124: *
0125: */
0126:
0127: package org.jfree.chart.plot;
0128:
0129: import java.awt.AlphaComposite;
0130: import java.awt.BasicStroke;
0131: import java.awt.Color;
0132: import java.awt.Composite;
0133: import java.awt.Font;
0134: import java.awt.GradientPaint;
0135: import java.awt.Graphics2D;
0136: import java.awt.Image;
0137: import java.awt.Paint;
0138: import java.awt.Shape;
0139: import java.awt.Stroke;
0140: import java.awt.geom.Ellipse2D;
0141: import java.awt.geom.Point2D;
0142: import java.awt.geom.Rectangle2D;
0143: import java.io.IOException;
0144: import java.io.ObjectInputStream;
0145: import java.io.ObjectOutputStream;
0146: import java.io.Serializable;
0147:
0148: import javax.swing.event.EventListenerList;
0149:
0150: import org.jfree.chart.LegendItemCollection;
0151: import org.jfree.chart.LegendItemSource;
0152: import org.jfree.chart.axis.AxisLocation;
0153: import org.jfree.chart.event.AxisChangeEvent;
0154: import org.jfree.chart.event.AxisChangeListener;
0155: import org.jfree.chart.event.ChartChangeEventType;
0156: import org.jfree.chart.event.MarkerChangeEvent;
0157: import org.jfree.chart.event.MarkerChangeListener;
0158: import org.jfree.chart.event.PlotChangeEvent;
0159: import org.jfree.chart.event.PlotChangeListener;
0160: import org.jfree.data.general.DatasetChangeEvent;
0161: import org.jfree.data.general.DatasetChangeListener;
0162: import org.jfree.data.general.DatasetGroup;
0163: import org.jfree.io.SerialUtilities;
0164: import org.jfree.text.G2TextMeasurer;
0165: import org.jfree.text.TextBlock;
0166: import org.jfree.text.TextBlockAnchor;
0167: import org.jfree.text.TextUtilities;
0168: import org.jfree.ui.Align;
0169: import org.jfree.ui.RectangleEdge;
0170: import org.jfree.ui.RectangleInsets;
0171: import org.jfree.util.ObjectUtilities;
0172: import org.jfree.util.PaintUtilities;
0173: import org.jfree.util.PublicCloneable;
0174:
0175: /**
0176: * The base class for all plots in JFreeChart. The
0177: * {@link org.jfree.chart.JFreeChart} class delegates the drawing of axes and
0178: * data to the plot. This base class provides facilities common to most plot
0179: * types.
0180: */
0181: public abstract class Plot implements AxisChangeListener,
0182: DatasetChangeListener, MarkerChangeListener, LegendItemSource,
0183: PublicCloneable, Cloneable, Serializable {
0184:
0185: /** For serialization. */
0186: private static final long serialVersionUID = -8831571430103671324L;
0187:
0188: /** Useful constant representing zero. */
0189: public static final Number ZERO = new Integer(0);
0190:
0191: /** The default insets. */
0192: public static final RectangleInsets DEFAULT_INSETS = new RectangleInsets(
0193: 4.0, 8.0, 4.0, 8.0);
0194:
0195: /** The default outline stroke. */
0196: public static final Stroke DEFAULT_OUTLINE_STROKE = new BasicStroke(
0197: 0.5f);
0198:
0199: /** The default outline color. */
0200: public static final Paint DEFAULT_OUTLINE_PAINT = Color.gray;
0201:
0202: /** The default foreground alpha transparency. */
0203: public static final float DEFAULT_FOREGROUND_ALPHA = 1.0f;
0204:
0205: /** The default background alpha transparency. */
0206: public static final float DEFAULT_BACKGROUND_ALPHA = 1.0f;
0207:
0208: /** The default background color. */
0209: public static final Paint DEFAULT_BACKGROUND_PAINT = Color.white;
0210:
0211: /** The minimum width at which the plot should be drawn. */
0212: public static final int MINIMUM_WIDTH_TO_DRAW = 10;
0213:
0214: /** The minimum height at which the plot should be drawn. */
0215: public static final int MINIMUM_HEIGHT_TO_DRAW = 10;
0216:
0217: /** A default box shape for legend items. */
0218: public static final Shape DEFAULT_LEGEND_ITEM_BOX = new Rectangle2D.Double(
0219: -4.0, -4.0, 8.0, 8.0);
0220:
0221: /** A default circle shape for legend items. */
0222: public static final Shape DEFAULT_LEGEND_ITEM_CIRCLE = new Ellipse2D.Double(
0223: -4.0, -4.0, 8.0, 8.0);
0224:
0225: /** The parent plot (<code>null</code> if this is the root plot). */
0226: private Plot parent;
0227:
0228: /** The dataset group (to be used for thread synchronisation). */
0229: private DatasetGroup datasetGroup;
0230:
0231: /** The message to display if no data is available. */
0232: private String noDataMessage;
0233:
0234: /** The font used to display the 'no data' message. */
0235: private Font noDataMessageFont;
0236:
0237: /** The paint used to draw the 'no data' message. */
0238: private transient Paint noDataMessagePaint;
0239:
0240: /** Amount of blank space around the plot area. */
0241: private RectangleInsets insets;
0242:
0243: /**
0244: * A flag that controls whether or not the plot outline is drawn.
0245: *
0246: * @since 1.0.6
0247: */
0248: private boolean outlineVisible;
0249:
0250: /** The Stroke used to draw an outline around the plot. */
0251: private transient Stroke outlineStroke;
0252:
0253: /** The Paint used to draw an outline around the plot. */
0254: private transient Paint outlinePaint;
0255:
0256: /** An optional color used to fill the plot background. */
0257: private transient Paint backgroundPaint;
0258:
0259: /** An optional image for the plot background. */
0260: private transient Image backgroundImage; // not currently serialized
0261:
0262: /** The alignment for the background image. */
0263: private int backgroundImageAlignment = Align.FIT;
0264:
0265: /** The alpha value used to draw the background image. */
0266: private float backgroundImageAlpha = 0.5f;
0267:
0268: /** The alpha-transparency for the plot. */
0269: private float foregroundAlpha;
0270:
0271: /** The alpha transparency for the background paint. */
0272: private float backgroundAlpha;
0273:
0274: /** The drawing supplier. */
0275: private DrawingSupplier drawingSupplier;
0276:
0277: /** Storage for registered change listeners. */
0278: private transient EventListenerList listenerList;
0279:
0280: /**
0281: * Creates a new plot.
0282: */
0283: protected Plot() {
0284:
0285: this .parent = null;
0286: this .insets = DEFAULT_INSETS;
0287: this .backgroundPaint = DEFAULT_BACKGROUND_PAINT;
0288: this .backgroundAlpha = DEFAULT_BACKGROUND_ALPHA;
0289: this .backgroundImage = null;
0290: this .outlineVisible = true;
0291: this .outlineStroke = DEFAULT_OUTLINE_STROKE;
0292: this .outlinePaint = DEFAULT_OUTLINE_PAINT;
0293: this .foregroundAlpha = DEFAULT_FOREGROUND_ALPHA;
0294:
0295: this .noDataMessage = null;
0296: this .noDataMessageFont = new Font("SansSerif", Font.PLAIN, 12);
0297: this .noDataMessagePaint = Color.black;
0298:
0299: this .drawingSupplier = new DefaultDrawingSupplier();
0300:
0301: this .listenerList = new EventListenerList();
0302:
0303: }
0304:
0305: /**
0306: * Returns the dataset group for the plot (not currently used).
0307: *
0308: * @return The dataset group.
0309: *
0310: * @see #setDatasetGroup(DatasetGroup)
0311: */
0312: public DatasetGroup getDatasetGroup() {
0313: return this .datasetGroup;
0314: }
0315:
0316: /**
0317: * Sets the dataset group (not currently used).
0318: *
0319: * @param group the dataset group (<code>null</code> permitted).
0320: *
0321: * @see #getDatasetGroup()
0322: */
0323: protected void setDatasetGroup(DatasetGroup group) {
0324: this .datasetGroup = group;
0325: }
0326:
0327: /**
0328: * Returns the string that is displayed when the dataset is empty or
0329: * <code>null</code>.
0330: *
0331: * @return The 'no data' message (<code>null</code> possible).
0332: *
0333: * @see #setNoDataMessage(String)
0334: * @see #getNoDataMessageFont()
0335: * @see #getNoDataMessagePaint()
0336: */
0337: public String getNoDataMessage() {
0338: return this .noDataMessage;
0339: }
0340:
0341: /**
0342: * Sets the message that is displayed when the dataset is empty or
0343: * <code>null</code>, and sends a {@link PlotChangeEvent} to all registered
0344: * listeners.
0345: *
0346: * @param message the message (<code>null</code> permitted).
0347: *
0348: * @see #getNoDataMessage()
0349: */
0350: public void setNoDataMessage(String message) {
0351: this .noDataMessage = message;
0352: notifyListeners(new PlotChangeEvent(this ));
0353: }
0354:
0355: /**
0356: * Returns the font used to display the 'no data' message.
0357: *
0358: * @return The font (never <code>null</code>).
0359: *
0360: * @see #setNoDataMessageFont(Font)
0361: * @see #getNoDataMessage()
0362: */
0363: public Font getNoDataMessageFont() {
0364: return this .noDataMessageFont;
0365: }
0366:
0367: /**
0368: * Sets the font used to display the 'no data' message and sends a
0369: * {@link PlotChangeEvent} to all registered listeners.
0370: *
0371: * @param font the font (<code>null</code> not permitted).
0372: *
0373: * @see #getNoDataMessageFont()
0374: */
0375: public void setNoDataMessageFont(Font font) {
0376: if (font == null) {
0377: throw new IllegalArgumentException("Null 'font' argument.");
0378: }
0379: this .noDataMessageFont = font;
0380: notifyListeners(new PlotChangeEvent(this ));
0381: }
0382:
0383: /**
0384: * Returns the paint used to display the 'no data' message.
0385: *
0386: * @return The paint (never <code>null</code>).
0387: *
0388: * @see #setNoDataMessagePaint(Paint)
0389: * @see #getNoDataMessage()
0390: */
0391: public Paint getNoDataMessagePaint() {
0392: return this .noDataMessagePaint;
0393: }
0394:
0395: /**
0396: * Sets the paint used to display the 'no data' message and sends a
0397: * {@link PlotChangeEvent} to all registered listeners.
0398: *
0399: * @param paint the paint (<code>null</code> not permitted).
0400: *
0401: * @see #getNoDataMessagePaint()
0402: */
0403: public void setNoDataMessagePaint(Paint paint) {
0404: if (paint == null) {
0405: throw new IllegalArgumentException("Null 'paint' argument.");
0406: }
0407: this .noDataMessagePaint = paint;
0408: notifyListeners(new PlotChangeEvent(this ));
0409: }
0410:
0411: /**
0412: * Returns a short string describing the plot type.
0413: * <P>
0414: * Note: this gets used in the chart property editing user interface,
0415: * but there needs to be a better mechanism for identifying the plot type.
0416: *
0417: * @return A short string describing the plot type (never
0418: * <code>null</code>).
0419: */
0420: public abstract String getPlotType();
0421:
0422: /**
0423: * Returns the parent plot (or <code>null</code> if this plot is not part
0424: * of a combined plot).
0425: *
0426: * @return The parent plot.
0427: *
0428: * @see #setParent(Plot)
0429: * @see #getRootPlot()
0430: */
0431: public Plot getParent() {
0432: return this .parent;
0433: }
0434:
0435: /**
0436: * Sets the parent plot. This method is intended for internal use, you
0437: * shouldn't need to call it directly.
0438: *
0439: * @param parent the parent plot (<code>null</code> permitted).
0440: *
0441: * @see #getParent()
0442: */
0443: public void setParent(Plot parent) {
0444: this .parent = parent;
0445: }
0446:
0447: /**
0448: * Returns the root plot.
0449: *
0450: * @return The root plot.
0451: *
0452: * @see #getParent()
0453: */
0454: public Plot getRootPlot() {
0455:
0456: Plot p = getParent();
0457: if (p == null) {
0458: return this ;
0459: } else {
0460: return p.getRootPlot();
0461: }
0462:
0463: }
0464:
0465: /**
0466: * Returns <code>true</code> if this plot is part of a combined plot
0467: * structure (that is, {@link #getParent()} returns a non-<code>null</code>
0468: * value), and <code>false</code> otherwise.
0469: *
0470: * @return <code>true</code> if this plot is part of a combined plot
0471: * structure.
0472: *
0473: * @see #getParent()
0474: */
0475: public boolean isSubplot() {
0476: return (getParent() != null);
0477: }
0478:
0479: /**
0480: * Returns the insets for the plot area.
0481: *
0482: * @return The insets (never <code>null</code>).
0483: *
0484: * @see #setInsets(RectangleInsets)
0485: */
0486: public RectangleInsets getInsets() {
0487: return this .insets;
0488: }
0489:
0490: /**
0491: * Sets the insets for the plot and sends a {@link PlotChangeEvent} to
0492: * all registered listeners.
0493: *
0494: * @param insets the new insets (<code>null</code> not permitted).
0495: *
0496: * @see #getInsets()
0497: * @see #setInsets(RectangleInsets, boolean)
0498: */
0499: public void setInsets(RectangleInsets insets) {
0500: setInsets(insets, true);
0501: }
0502:
0503: /**
0504: * Sets the insets for the plot and, if requested, and sends a
0505: * {@link PlotChangeEvent} to all registered listeners.
0506: *
0507: * @param insets the new insets (<code>null</code> not permitted).
0508: * @param notify a flag that controls whether the registered listeners are
0509: * notified.
0510: *
0511: * @see #getInsets()
0512: * @see #setInsets(RectangleInsets)
0513: */
0514: public void setInsets(RectangleInsets insets, boolean notify) {
0515: if (insets == null) {
0516: throw new IllegalArgumentException(
0517: "Null 'insets' argument.");
0518: }
0519: if (!this .insets.equals(insets)) {
0520: this .insets = insets;
0521: if (notify) {
0522: notifyListeners(new PlotChangeEvent(this ));
0523: }
0524: }
0525:
0526: }
0527:
0528: /**
0529: * Returns the background color of the plot area.
0530: *
0531: * @return The paint (possibly <code>null</code>).
0532: *
0533: * @see #setBackgroundPaint(Paint)
0534: */
0535: public Paint getBackgroundPaint() {
0536: return this .backgroundPaint;
0537: }
0538:
0539: /**
0540: * Sets the background color of the plot area and sends a
0541: * {@link PlotChangeEvent} to all registered listeners.
0542: *
0543: * @param paint the paint (<code>null</code> permitted).
0544: *
0545: * @see #getBackgroundPaint()
0546: */
0547: public void setBackgroundPaint(Paint paint) {
0548:
0549: if (paint == null) {
0550: if (this .backgroundPaint != null) {
0551: this .backgroundPaint = null;
0552: notifyListeners(new PlotChangeEvent(this ));
0553: }
0554: } else {
0555: if (this .backgroundPaint != null) {
0556: if (this .backgroundPaint.equals(paint)) {
0557: return; // nothing to do
0558: }
0559: }
0560: this .backgroundPaint = paint;
0561: notifyListeners(new PlotChangeEvent(this ));
0562: }
0563:
0564: }
0565:
0566: /**
0567: * Returns the alpha transparency of the plot area background.
0568: *
0569: * @return The alpha transparency.
0570: *
0571: * @see #setBackgroundAlpha(float)
0572: */
0573: public float getBackgroundAlpha() {
0574: return this .backgroundAlpha;
0575: }
0576:
0577: /**
0578: * Sets the alpha transparency of the plot area background, and notifies
0579: * registered listeners that the plot has been modified.
0580: *
0581: * @param alpha the new alpha value (in the range 0.0f to 1.0f).
0582: *
0583: * @see #getBackgroundAlpha()
0584: */
0585: public void setBackgroundAlpha(float alpha) {
0586: if (this .backgroundAlpha != alpha) {
0587: this .backgroundAlpha = alpha;
0588: notifyListeners(new PlotChangeEvent(this ));
0589: }
0590: }
0591:
0592: /**
0593: * Returns the drawing supplier for the plot.
0594: *
0595: * @return The drawing supplier (possibly <code>null</code>).
0596: *
0597: * @see #setDrawingSupplier(DrawingSupplier)
0598: */
0599: public DrawingSupplier getDrawingSupplier() {
0600: DrawingSupplier result = null;
0601: Plot p = getParent();
0602: if (p != null) {
0603: result = p.getDrawingSupplier();
0604: } else {
0605: result = this .drawingSupplier;
0606: }
0607: return result;
0608: }
0609:
0610: /**
0611: * Sets the drawing supplier for the plot. The drawing supplier is
0612: * responsible for supplying a limitless (possibly repeating) sequence of
0613: * <code>Paint</code>, <code>Stroke</code> and <code>Shape</code> objects
0614: * that the plot's renderer(s) can use to populate its (their) tables.
0615: *
0616: * @param supplier the new supplier.
0617: *
0618: * @see #getDrawingSupplier()
0619: */
0620: public void setDrawingSupplier(DrawingSupplier supplier) {
0621: this .drawingSupplier = supplier;
0622: notifyListeners(new PlotChangeEvent(this ));
0623: }
0624:
0625: /**
0626: * Returns the background image that is used to fill the plot's background
0627: * area.
0628: *
0629: * @return The image (possibly <code>null</code>).
0630: *
0631: * @see #setBackgroundImage(Image)
0632: */
0633: public Image getBackgroundImage() {
0634: return this .backgroundImage;
0635: }
0636:
0637: /**
0638: * Sets the background image for the plot and sends a
0639: * {@link PlotChangeEvent} to all registered listeners.
0640: *
0641: * @param image the image (<code>null</code> permitted).
0642: *
0643: * @see #getBackgroundImage()
0644: */
0645: public void setBackgroundImage(Image image) {
0646: this .backgroundImage = image;
0647: notifyListeners(new PlotChangeEvent(this ));
0648: }
0649:
0650: /**
0651: * Returns the background image alignment. Alignment constants are defined
0652: * in the <code>org.jfree.ui.Align</code> class in the JCommon class
0653: * library.
0654: *
0655: * @return The alignment.
0656: *
0657: * @see #setBackgroundImageAlignment(int)
0658: */
0659: public int getBackgroundImageAlignment() {
0660: return this .backgroundImageAlignment;
0661: }
0662:
0663: /**
0664: * Sets the alignment for the background image and sends a
0665: * {@link PlotChangeEvent} to all registered listeners. Alignment options
0666: * are defined by the {@link org.jfree.ui.Align} class in the JCommon
0667: * class library.
0668: *
0669: * @param alignment the alignment.
0670: *
0671: * @see #getBackgroundImageAlignment()
0672: */
0673: public void setBackgroundImageAlignment(int alignment) {
0674: if (this .backgroundImageAlignment != alignment) {
0675: this .backgroundImageAlignment = alignment;
0676: notifyListeners(new PlotChangeEvent(this ));
0677: }
0678: }
0679:
0680: /**
0681: * Returns the alpha transparency used to draw the background image. This
0682: * is a value in the range 0.0f to 1.0f, where 0.0f is fully transparent
0683: * and 1.0f is fully opaque.
0684: *
0685: * @return The alpha transparency.
0686: *
0687: * @see #setBackgroundImageAlpha(float)
0688: */
0689: public float getBackgroundImageAlpha() {
0690: return this .backgroundImageAlpha;
0691: }
0692:
0693: /**
0694: * Sets the alpha transparency used when drawing the background image.
0695: *
0696: * @param alpha the alpha transparency (in the range 0.0f to 1.0f, where
0697: * 0.0f is fully transparent, and 1.0f is fully opaque).
0698: *
0699: * @throws IllegalArgumentException if <code>alpha</code> is not within
0700: * the specified range.
0701: *
0702: * @see #getBackgroundImageAlpha()
0703: */
0704: public void setBackgroundImageAlpha(float alpha) {
0705: if (alpha < 0.0f || alpha > 1.0f)
0706: throw new IllegalArgumentException(
0707: "The 'alpha' value must be in the range 0.0f to 1.0f.");
0708: if (this .backgroundImageAlpha != alpha) {
0709: this .backgroundImageAlpha = alpha;
0710: this .notifyListeners(new PlotChangeEvent(this ));
0711: }
0712: }
0713:
0714: /**
0715: * Returns the flag that controls whether or not the plot outline is
0716: * drawn. The default value is <code>true</code>. Note that for
0717: * historical reasons, the plot's outline paint and stroke can take on
0718: * <code>null</code> values, in which case the outline will not be drawn
0719: * even if this flag is set to <code>true</code>.
0720: *
0721: * @return The outline visibility flag.
0722: *
0723: * @since 1.0.6
0724: *
0725: * @see #setOutlineVisible(boolean)
0726: */
0727: public boolean isOutlineVisible() {
0728: return this .outlineVisible;
0729: }
0730:
0731: /**
0732: * Sets the flag that controls whether or not the plot's outline is
0733: * drawn, and sends a {@link PlotChangeEvent} to all registered listeners.
0734: *
0735: * @param visible the new flag value.
0736: *
0737: * @since 1.0.6
0738: *
0739: * @see #isOutlineVisible()
0740: */
0741: public void setOutlineVisible(boolean visible) {
0742: this .outlineVisible = visible;
0743: notifyListeners(new PlotChangeEvent(this ));
0744: }
0745:
0746: /**
0747: * Returns the stroke used to outline the plot area.
0748: *
0749: * @return The stroke (possibly <code>null</code>).
0750: *
0751: * @see #setOutlineStroke(Stroke)
0752: */
0753: public Stroke getOutlineStroke() {
0754: return this .outlineStroke;
0755: }
0756:
0757: /**
0758: * Sets the stroke used to outline the plot area and sends a
0759: * {@link PlotChangeEvent} to all registered listeners. If you set this
0760: * attribute to <code>null</code>, no outline will be drawn.
0761: *
0762: * @param stroke the stroke (<code>null</code> permitted).
0763: *
0764: * @see #getOutlineStroke()
0765: */
0766: public void setOutlineStroke(Stroke stroke) {
0767: if (stroke == null) {
0768: if (this .outlineStroke != null) {
0769: this .outlineStroke = null;
0770: notifyListeners(new PlotChangeEvent(this ));
0771: }
0772: } else {
0773: if (this .outlineStroke != null) {
0774: if (this .outlineStroke.equals(stroke)) {
0775: return; // nothing to do
0776: }
0777: }
0778: this .outlineStroke = stroke;
0779: notifyListeners(new PlotChangeEvent(this ));
0780: }
0781: }
0782:
0783: /**
0784: * Returns the color used to draw the outline of the plot area.
0785: *
0786: * @return The color (possibly <code>null<code>).
0787: *
0788: * @see #setOutlinePaint(Paint)
0789: */
0790: public Paint getOutlinePaint() {
0791: return this .outlinePaint;
0792: }
0793:
0794: /**
0795: * Sets the paint used to draw the outline of the plot area and sends a
0796: * {@link PlotChangeEvent} to all registered listeners. If you set this
0797: * attribute to <code>null</code>, no outline will be drawn.
0798: *
0799: * @param paint the paint (<code>null</code> permitted).
0800: *
0801: * @see #getOutlinePaint()
0802: */
0803: public void setOutlinePaint(Paint paint) {
0804: if (paint == null) {
0805: if (this .outlinePaint != null) {
0806: this .outlinePaint = null;
0807: notifyListeners(new PlotChangeEvent(this ));
0808: }
0809: } else {
0810: if (this .outlinePaint != null) {
0811: if (this .outlinePaint.equals(paint)) {
0812: return; // nothing to do
0813: }
0814: }
0815: this .outlinePaint = paint;
0816: notifyListeners(new PlotChangeEvent(this ));
0817: }
0818: }
0819:
0820: /**
0821: * Returns the alpha-transparency for the plot foreground.
0822: *
0823: * @return The alpha-transparency.
0824: *
0825: * @see #setForegroundAlpha(float)
0826: */
0827: public float getForegroundAlpha() {
0828: return this .foregroundAlpha;
0829: }
0830:
0831: /**
0832: * Sets the alpha-transparency for the plot and sends a
0833: * {@link PlotChangeEvent} to all registered listeners.
0834: *
0835: * @param alpha the new alpha transparency.
0836: *
0837: * @see #getForegroundAlpha()
0838: */
0839: public void setForegroundAlpha(float alpha) {
0840: if (this .foregroundAlpha != alpha) {
0841: this .foregroundAlpha = alpha;
0842: notifyListeners(new PlotChangeEvent(this ));
0843: }
0844: }
0845:
0846: /**
0847: * Returns the legend items for the plot. By default, this method returns
0848: * <code>null</code>. Subclasses should override to return a
0849: * {@link LegendItemCollection}.
0850: *
0851: * @return The legend items for the plot (possibly <code>null</code>).
0852: */
0853: public LegendItemCollection getLegendItems() {
0854: return null;
0855: }
0856:
0857: /**
0858: * Registers an object for notification of changes to the plot.
0859: *
0860: * @param listener the object to be registered.
0861: *
0862: * @see #removeChangeListener(PlotChangeListener)
0863: */
0864: public void addChangeListener(PlotChangeListener listener) {
0865: this .listenerList.add(PlotChangeListener.class, listener);
0866: }
0867:
0868: /**
0869: * Unregisters an object for notification of changes to the plot.
0870: *
0871: * @param listener the object to be unregistered.
0872: *
0873: * @see #addChangeListener(PlotChangeListener)
0874: */
0875: public void removeChangeListener(PlotChangeListener listener) {
0876: this .listenerList.remove(PlotChangeListener.class, listener);
0877: }
0878:
0879: /**
0880: * Notifies all registered listeners that the plot has been modified.
0881: *
0882: * @param event information about the change event.
0883: */
0884: public void notifyListeners(PlotChangeEvent event) {
0885: Object[] listeners = this .listenerList.getListenerList();
0886: for (int i = listeners.length - 2; i >= 0; i -= 2) {
0887: if (listeners[i] == PlotChangeListener.class) {
0888: ((PlotChangeListener) listeners[i + 1])
0889: .plotChanged(event);
0890: }
0891: }
0892: }
0893:
0894: /**
0895: * Draws the plot within the specified area. The anchor is a point on the
0896: * chart that is specified externally (for instance, it may be the last
0897: * point of the last mouse click performed by the user) - plots can use or
0898: * ignore this value as they see fit.
0899: * <br><br>
0900: * Subclasses need to provide an implementation of this method, obviously.
0901: *
0902: * @param g2 the graphics device.
0903: * @param area the plot area.
0904: * @param anchor the anchor point (<code>null</code> permitted).
0905: * @param parentState the parent state (if any).
0906: * @param info carries back plot rendering info.
0907: */
0908: public abstract void draw(Graphics2D g2, Rectangle2D area,
0909: Point2D anchor, PlotState parentState,
0910: PlotRenderingInfo info);
0911:
0912: /**
0913: * Draws the plot background (the background color and/or image).
0914: * <P>
0915: * This method will be called during the chart drawing process and is
0916: * declared public so that it can be accessed by the renderers used by
0917: * certain subclasses. You shouldn't need to call this method directly.
0918: *
0919: * @param g2 the graphics device.
0920: * @param area the area within which the plot should be drawn.
0921: */
0922: public void drawBackground(Graphics2D g2, Rectangle2D area) {
0923: // some subclasses override this method completely, so don't put
0924: // anything here that *must* be done
0925: fillBackground(g2, area);
0926: drawBackgroundImage(g2, area);
0927: }
0928:
0929: /**
0930: * Fills the specified area with the background paint.
0931: *
0932: * @param g2 the graphics device.
0933: * @param area the area.
0934: *
0935: * @see #getBackgroundPaint()
0936: * @see #getBackgroundAlpha()
0937: * @see #fillBackground(Graphics2D, Rectangle2D, PlotOrientation)
0938: */
0939: protected void fillBackground(Graphics2D g2, Rectangle2D area) {
0940: fillBackground(g2, area, PlotOrientation.VERTICAL);
0941: }
0942:
0943: /**
0944: * Fills the specified area with the background paint. If the background
0945: * paint is an instance of <code>GradientPaint</code>, the gradient will
0946: * run in the direction suggested by the plot's orientation.
0947: *
0948: * @param g2 the graphics target.
0949: * @param area the plot area.
0950: * @param orientation the plot orientation (<code>null</code> not
0951: * permitted).
0952: *
0953: * @since 1.0.6
0954: */
0955: protected void fillBackground(Graphics2D g2, Rectangle2D area,
0956: PlotOrientation orientation) {
0957: if (orientation == null) {
0958: throw new IllegalArgumentException(
0959: "Null 'orientation' argument.");
0960: }
0961: if (this .backgroundPaint == null) {
0962: return;
0963: }
0964: Paint p = this .backgroundPaint;
0965: if (p instanceof GradientPaint) {
0966: GradientPaint gp = (GradientPaint) p;
0967: if (orientation == PlotOrientation.VERTICAL) {
0968: p = new GradientPaint((float) area.getCenterX(),
0969: (float) area.getMaxY(), gp.getColor1(),
0970: (float) area.getCenterX(), (float) area
0971: .getMinY(), gp.getColor2());
0972: } else if (orientation == PlotOrientation.HORIZONTAL) {
0973: p = new GradientPaint((float) area.getMinX(),
0974: (float) area.getCenterY(), gp.getColor1(),
0975: (float) area.getMaxX(), (float) area
0976: .getCenterY(), gp.getColor2());
0977: }
0978: }
0979: Composite originalComposite = g2.getComposite();
0980: g2.setComposite(AlphaComposite.getInstance(
0981: AlphaComposite.SRC_OVER, this .backgroundAlpha));
0982: g2.setPaint(p);
0983: g2.fill(area);
0984: g2.setComposite(originalComposite);
0985: }
0986:
0987: /**
0988: * Draws the background image (if there is one) aligned within the
0989: * specified area.
0990: *
0991: * @param g2 the graphics device.
0992: * @param area the area.
0993: *
0994: * @see #getBackgroundImage()
0995: * @see #getBackgroundImageAlignment()
0996: * @see #getBackgroundImageAlpha()
0997: */
0998: public void drawBackgroundImage(Graphics2D g2, Rectangle2D area) {
0999: if (this .backgroundImage != null) {
1000: Composite originalComposite = g2.getComposite();
1001: g2
1002: .setComposite(AlphaComposite.getInstance(
1003: AlphaComposite.SRC_OVER,
1004: this .backgroundImageAlpha));
1005: Rectangle2D dest = new Rectangle2D.Double(0.0, 0.0,
1006: this .backgroundImage.getWidth(null),
1007: this .backgroundImage.getHeight(null));
1008: Align.align(dest, area, this .backgroundImageAlignment);
1009: g2.drawImage(this .backgroundImage, (int) dest.getX(),
1010: (int) dest.getY(), (int) dest.getWidth() + 1,
1011: (int) dest.getHeight() + 1, null);
1012: g2.setComposite(originalComposite);
1013: }
1014: }
1015:
1016: /**
1017: * Draws the plot outline. This method will be called during the chart
1018: * drawing process and is declared public so that it can be accessed by the
1019: * renderers used by certain subclasses. You shouldn't need to call this
1020: * method directly.
1021: *
1022: * @param g2 the graphics device.
1023: * @param area the area within which the plot should be drawn.
1024: */
1025: public void drawOutline(Graphics2D g2, Rectangle2D area) {
1026: if (!this .outlineVisible) {
1027: return;
1028: }
1029: if ((this .outlineStroke != null) && (this .outlinePaint != null)) {
1030: g2.setStroke(this .outlineStroke);
1031: g2.setPaint(this .outlinePaint);
1032: g2.draw(area);
1033: }
1034: }
1035:
1036: /**
1037: * Draws a message to state that there is no data to plot.
1038: *
1039: * @param g2 the graphics device.
1040: * @param area the area within which the plot should be drawn.
1041: */
1042: protected void drawNoDataMessage(Graphics2D g2, Rectangle2D area) {
1043: Shape savedClip = g2.getClip();
1044: g2.clip(area);
1045: String message = this .noDataMessage;
1046: if (message != null) {
1047: g2.setFont(this .noDataMessageFont);
1048: g2.setPaint(this .noDataMessagePaint);
1049: TextBlock block = TextUtilities.createTextBlock(
1050: this .noDataMessage, this .noDataMessageFont,
1051: this .noDataMessagePaint, 0.9f * (float) area
1052: .getWidth(), new G2TextMeasurer(g2));
1053: block.draw(g2, (float) area.getCenterX(), (float) area
1054: .getCenterY(), TextBlockAnchor.CENTER);
1055: }
1056: g2.setClip(savedClip);
1057: }
1058:
1059: /**
1060: * Handles a 'click' on the plot. Since the plot does not maintain any
1061: * information about where it has been drawn, the plot rendering info is
1062: * supplied as an argument.
1063: *
1064: * @param x the x coordinate (in Java2D space).
1065: * @param y the y coordinate (in Java2D space).
1066: * @param info an object containing information about the dimensions of
1067: * the plot.
1068: */
1069: public void handleClick(int x, int y, PlotRenderingInfo info) {
1070: // provides a 'no action' default
1071: }
1072:
1073: /**
1074: * Performs a zoom on the plot. Subclasses should override if zooming is
1075: * appropriate for the type of plot.
1076: *
1077: * @param percent the zoom percentage.
1078: */
1079: public void zoom(double percent) {
1080: // do nothing by default.
1081: }
1082:
1083: /**
1084: * Receives notification of a change to one of the plot's axes.
1085: *
1086: * @param event information about the event (not used here).
1087: */
1088: public void axisChanged(AxisChangeEvent event) {
1089: notifyListeners(new PlotChangeEvent(this ));
1090: }
1091:
1092: /**
1093: * Receives notification of a change to the plot's dataset.
1094: * <P>
1095: * The plot reacts by passing on a plot change event to all registered
1096: * listeners.
1097: *
1098: * @param event information about the event (not used here).
1099: */
1100: public void datasetChanged(DatasetChangeEvent event) {
1101: PlotChangeEvent newEvent = new PlotChangeEvent(this );
1102: newEvent.setType(ChartChangeEventType.DATASET_UPDATED);
1103: notifyListeners(newEvent);
1104: }
1105:
1106: /**
1107: * Receives notification of a change to a marker that is assigned to the
1108: * plot.
1109: *
1110: * @param event the event.
1111: *
1112: * @since 1.0.3
1113: */
1114: public void markerChanged(MarkerChangeEvent event) {
1115: notifyListeners(new PlotChangeEvent(this ));
1116: }
1117:
1118: /**
1119: * Adjusts the supplied x-value.
1120: *
1121: * @param x the x-value.
1122: * @param w1 width 1.
1123: * @param w2 width 2.
1124: * @param edge the edge (left or right).
1125: *
1126: * @return The adjusted x-value.
1127: */
1128: protected double getRectX(double x, double w1, double w2,
1129: RectangleEdge edge) {
1130:
1131: double result = x;
1132: if (edge == RectangleEdge.LEFT) {
1133: result = result + w1;
1134: } else if (edge == RectangleEdge.RIGHT) {
1135: result = result + w2;
1136: }
1137: return result;
1138:
1139: }
1140:
1141: /**
1142: * Adjusts the supplied y-value.
1143: *
1144: * @param y the x-value.
1145: * @param h1 height 1.
1146: * @param h2 height 2.
1147: * @param edge the edge (top or bottom).
1148: *
1149: * @return The adjusted y-value.
1150: */
1151: protected double getRectY(double y, double h1, double h2,
1152: RectangleEdge edge) {
1153:
1154: double result = y;
1155: if (edge == RectangleEdge.TOP) {
1156: result = result + h1;
1157: } else if (edge == RectangleEdge.BOTTOM) {
1158: result = result + h2;
1159: }
1160: return result;
1161:
1162: }
1163:
1164: /**
1165: * Tests this plot for equality with another object.
1166: *
1167: * @param obj the object (<code>null</code> permitted).
1168: *
1169: * @return <code>true</code> or <code>false</code>.
1170: */
1171: public boolean equals(Object obj) {
1172: if (obj == this ) {
1173: return true;
1174: }
1175: if (!(obj instanceof Plot)) {
1176: return false;
1177: }
1178: Plot that = (Plot) obj;
1179: if (!ObjectUtilities.equal(this .noDataMessage,
1180: that.noDataMessage)) {
1181: return false;
1182: }
1183: if (!ObjectUtilities.equal(this .noDataMessageFont,
1184: that.noDataMessageFont)) {
1185: return false;
1186: }
1187: if (!PaintUtilities.equal(this .noDataMessagePaint,
1188: that.noDataMessagePaint)) {
1189: return false;
1190: }
1191: if (!ObjectUtilities.equal(this .insets, that.insets)) {
1192: return false;
1193: }
1194: if (this .outlineVisible != that.outlineVisible) {
1195: return false;
1196: }
1197: if (!ObjectUtilities.equal(this .outlineStroke,
1198: that.outlineStroke)) {
1199: return false;
1200: }
1201: if (!PaintUtilities.equal(this .outlinePaint, that.outlinePaint)) {
1202: return false;
1203: }
1204: if (!PaintUtilities.equal(this .backgroundPaint,
1205: that.backgroundPaint)) {
1206: return false;
1207: }
1208: if (!ObjectUtilities.equal(this .backgroundImage,
1209: that.backgroundImage)) {
1210: return false;
1211: }
1212: if (this .backgroundImageAlignment != that.backgroundImageAlignment) {
1213: return false;
1214: }
1215: if (this .backgroundImageAlpha != that.backgroundImageAlpha) {
1216: return false;
1217: }
1218: if (this .foregroundAlpha != that.foregroundAlpha) {
1219: return false;
1220: }
1221: if (this .backgroundAlpha != that.backgroundAlpha) {
1222: return false;
1223: }
1224: if (!this .drawingSupplier.equals(that.drawingSupplier)) {
1225: return false;
1226: }
1227: return true;
1228: }
1229:
1230: /**
1231: * Creates a clone of the plot.
1232: *
1233: * @return A clone.
1234: *
1235: * @throws CloneNotSupportedException if some component of the plot does not
1236: * support cloning.
1237: */
1238: public Object clone() throws CloneNotSupportedException {
1239:
1240: Plot clone = (Plot) super .clone();
1241: // private Plot parent <-- don't clone the parent plot, but take care
1242: // childs in combined plots instead
1243: if (this .datasetGroup != null) {
1244: clone.datasetGroup = (DatasetGroup) ObjectUtilities
1245: .clone(this .datasetGroup);
1246: }
1247: clone.drawingSupplier = (DrawingSupplier) ObjectUtilities
1248: .clone(this .drawingSupplier);
1249: clone.listenerList = new EventListenerList();
1250: return clone;
1251:
1252: }
1253:
1254: /**
1255: * Provides serialization support.
1256: *
1257: * @param stream the output stream.
1258: *
1259: * @throws IOException if there is an I/O error.
1260: */
1261: private void writeObject(ObjectOutputStream stream)
1262: throws IOException {
1263: stream.defaultWriteObject();
1264: SerialUtilities.writePaint(this .noDataMessagePaint, stream);
1265: SerialUtilities.writeStroke(this .outlineStroke, stream);
1266: SerialUtilities.writePaint(this .outlinePaint, stream);
1267: // backgroundImage
1268: SerialUtilities.writePaint(this .backgroundPaint, stream);
1269: }
1270:
1271: /**
1272: * Provides serialization support.
1273: *
1274: * @param stream the input stream.
1275: *
1276: * @throws IOException if there is an I/O error.
1277: * @throws ClassNotFoundException if there is a classpath problem.
1278: */
1279: private void readObject(ObjectInputStream stream)
1280: throws IOException, ClassNotFoundException {
1281: stream.defaultReadObject();
1282: this .noDataMessagePaint = SerialUtilities.readPaint(stream);
1283: this .outlineStroke = SerialUtilities.readStroke(stream);
1284: this .outlinePaint = SerialUtilities.readPaint(stream);
1285: // backgroundImage
1286: this .backgroundPaint = SerialUtilities.readPaint(stream);
1287:
1288: this .listenerList = new EventListenerList();
1289:
1290: }
1291:
1292: /**
1293: * Resolves a domain axis location for a given plot orientation.
1294: *
1295: * @param location the location (<code>null</code> not permitted).
1296: * @param orientation the orientation (<code>null</code> not permitted).
1297: *
1298: * @return The edge (never <code>null</code>).
1299: */
1300: public static RectangleEdge resolveDomainAxisLocation(
1301: AxisLocation location, PlotOrientation orientation) {
1302:
1303: if (location == null) {
1304: throw new IllegalArgumentException(
1305: "Null 'location' argument.");
1306: }
1307: if (orientation == null) {
1308: throw new IllegalArgumentException(
1309: "Null 'orientation' argument.");
1310: }
1311:
1312: RectangleEdge result = null;
1313:
1314: if (location == AxisLocation.TOP_OR_RIGHT) {
1315: if (orientation == PlotOrientation.HORIZONTAL) {
1316: result = RectangleEdge.RIGHT;
1317: } else if (orientation == PlotOrientation.VERTICAL) {
1318: result = RectangleEdge.TOP;
1319: }
1320: } else if (location == AxisLocation.TOP_OR_LEFT) {
1321: if (orientation == PlotOrientation.HORIZONTAL) {
1322: result = RectangleEdge.LEFT;
1323: } else if (orientation == PlotOrientation.VERTICAL) {
1324: result = RectangleEdge.TOP;
1325: }
1326: } else if (location == AxisLocation.BOTTOM_OR_RIGHT) {
1327: if (orientation == PlotOrientation.HORIZONTAL) {
1328: result = RectangleEdge.RIGHT;
1329: } else if (orientation == PlotOrientation.VERTICAL) {
1330: result = RectangleEdge.BOTTOM;
1331: }
1332: } else if (location == AxisLocation.BOTTOM_OR_LEFT) {
1333: if (orientation == PlotOrientation.HORIZONTAL) {
1334: result = RectangleEdge.LEFT;
1335: } else if (orientation == PlotOrientation.VERTICAL) {
1336: result = RectangleEdge.BOTTOM;
1337: }
1338: }
1339: // the above should cover all the options...
1340: if (result == null) {
1341: throw new IllegalStateException(
1342: "resolveDomainAxisLocation()");
1343: }
1344: return result;
1345:
1346: }
1347:
1348: /**
1349: * Resolves a range axis location for a given plot orientation.
1350: *
1351: * @param location the location (<code>null</code> not permitted).
1352: * @param orientation the orientation (<code>null</code> not permitted).
1353: *
1354: * @return The edge (never <code>null</code>).
1355: */
1356: public static RectangleEdge resolveRangeAxisLocation(
1357: AxisLocation location, PlotOrientation orientation) {
1358:
1359: if (location == null) {
1360: throw new IllegalArgumentException(
1361: "Null 'location' argument.");
1362: }
1363: if (orientation == null) {
1364: throw new IllegalArgumentException(
1365: "Null 'orientation' argument.");
1366: }
1367:
1368: RectangleEdge result = null;
1369:
1370: if (location == AxisLocation.TOP_OR_RIGHT) {
1371: if (orientation == PlotOrientation.HORIZONTAL) {
1372: result = RectangleEdge.TOP;
1373: } else if (orientation == PlotOrientation.VERTICAL) {
1374: result = RectangleEdge.RIGHT;
1375: }
1376: } else if (location == AxisLocation.TOP_OR_LEFT) {
1377: if (orientation == PlotOrientation.HORIZONTAL) {
1378: result = RectangleEdge.TOP;
1379: } else if (orientation == PlotOrientation.VERTICAL) {
1380: result = RectangleEdge.LEFT;
1381: }
1382: } else if (location == AxisLocation.BOTTOM_OR_RIGHT) {
1383: if (orientation == PlotOrientation.HORIZONTAL) {
1384: result = RectangleEdge.BOTTOM;
1385: } else if (orientation == PlotOrientation.VERTICAL) {
1386: result = RectangleEdge.RIGHT;
1387: }
1388: } else if (location == AxisLocation.BOTTOM_OR_LEFT) {
1389: if (orientation == PlotOrientation.HORIZONTAL) {
1390: result = RectangleEdge.BOTTOM;
1391: } else if (orientation == PlotOrientation.VERTICAL) {
1392: result = RectangleEdge.LEFT;
1393: }
1394: }
1395:
1396: // the above should cover all the options...
1397: if (result == null) {
1398: throw new IllegalStateException(
1399: "resolveRangeAxisLocation()");
1400: }
1401: return result;
1402:
1403: }
1404:
1405: }
|