KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > plot > Plot


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2005, 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 License
20  * along with this library; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
24  * in the United States and other countries.]
25  *
26  * ---------
27  * Plot.java
28  * ---------
29  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
30  *
31  * Original Author: David Gilbert (for Object Refinery Limited);
32  * Contributor(s): Sylvain Vieujot;
33  * Jeremy Bowman;
34  * Andreas Schneider;
35  * Gideon Krause;
36  * Nicolas Brodu;
37  *
38  * $Id: Plot.java,v 1.18 2005/05/19 14:03:40 mungady Exp $
39  *
40  * Changes (from 21-Jun-2001)
41  * --------------------------
42  * 21-Jun-2001 : Removed redundant JFreeChart parameter from constructors (DG);
43  * 18-Sep-2001 : Updated header info and fixed DOS encoding problem (DG);
44  * 19-Oct-2001 : Moved series paint and stroke methods from JFreeChart
45  * class (DG);
46  * 23-Oct-2001 : Created renderer for LinePlot class (DG);
47  * 07-Nov-2001 : Changed type names for ChartChangeEvent (DG);
48  * Tidied up some Javadoc comments (DG);
49  * 13-Nov-2001 : Changes to allow for null axes on plots such as PiePlot (DG);
50  * Added plot/axis compatibility checks (DG);
51  * 12-Dec-2001 : Changed constructors to protected, and removed unnecessary
52  * 'throws' clauses (DG);
53  * 13-Dec-2001 : Added tooltips (DG);
54  * 22-Jan-2002 : Added handleClick() method, as part of implementation for
55  * crosshairs (DG);
56  * Moved tooltips reference into ChartInfo class (DG);
57  * 23-Jan-2002 : Added test for null axes in chartChanged() method, thanks
58  * to Barry Evans for the bug report (number 506979 on
59  * SourceForge) (DG);
60  * Added a zoom() method (DG);
61  * 05-Feb-2002 : Updated setBackgroundPaint(), setOutlineStroke() and
62  * setOutlinePaint() to better handle null values, as suggested
63  * by Sylvain Vieujot (DG);
64  * 06-Feb-2002 : Added background image, plus alpha transparency for background
65  * and foreground (DG);
66  * 06-Mar-2002 : Added AxisConstants interface (DG);
67  * 26-Mar-2002 : Changed zoom method from empty to abstract (DG);
68  * 23-Apr-2002 : Moved dataset from JFreeChart class (DG);
69  * 11-May-2002 : Added ShapeFactory interface for getShape() methods,
70  * contributed by Jeremy Bowman (DG);
71  * 28-May-2002 : Fixed bug in setSeriesPaint(int, Paint) for subplots (AS);
72  * 25-Jun-2002 : Removed redundant imports (DG);
73  * 30-Jul-2002 : Added 'no data' message for charts with null or empty
74  * datasets (DG);
75  * 21-Aug-2002 : Added code to extend series array if necessary (refer to
76  * SourceForge bug id 594547 for details) (DG);
77  * 17-Sep-2002 : Fixed bug in getSeriesOutlineStroke() method, reported by
78  * Andreas Schroeder (DG);
79  * 23-Sep-2002 : Added getLegendItems() abstract method (DG);
80  * 24-Sep-2002 : Removed firstSeriesIndex, subplots now use their own paint
81  * settings, there is a new mechanism for the legend to collect
82  * the legend items (DG);
83  * 27-Sep-2002 : Added dataset group (DG);
84  * 14-Oct-2002 : Moved listener storage into EventListenerList. Changed some
85  * abstract methods to empty implementations (DG);
86  * 28-Oct-2002 : Added a getBackgroundImage() method (DG);
87  * 21-Nov-2002 : Added a plot index for identifying subplots in combined and
88  * overlaid charts (DG);
89  * 22-Nov-2002 : Changed all attributes from 'protected' to 'private'. Added
90  * dataAreaRatio attribute from David M O'Donnell's code (DG);
91  * 09-Jan-2003 : Integrated fix for plot border contributed by Gideon
92  * Krause (DG);
93  * 17-Jan-2003 : Moved to com.jrefinery.chart.plot (DG);
94  * 23-Jan-2003 : Removed one constructor (DG);
95  * 26-Mar-2003 : Implemented Serializable (DG);
96  * 14-Jul-2003 : Moved the dataset and secondaryDataset attributes to the
97  * CategoryPlot and XYPlot classes (DG);
98  * 21-Jul-2003 : Moved DrawingSupplier from CategoryPlot and XYPlot up to this
99  * class (DG);
100  * 20-Aug-2003 : Implemented Cloneable (DG);
101  * 11-Sep-2003 : Listeners and clone (NB);
102  * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
103  * 03-Dec-2003 : Modified draw method to accept anchor (DG);
104  * 12-Mar-2004 : Fixed clipping bug in drawNoDataMessage() method (DG);
105  * 07-Apr-2004 : Modified string bounds calculation (DG);
106  * 04-Nov-2004 : Added default shapes for legend items (DG);
107  * 25-Nov-2004 : Some changes to the clone() method implementation (DG);
108  * 23-Feb-2005 : Implemented new LegendItemSource interface (and also
109  * PublicCloneable) (DG);
110  * 21-Apr-2005 : Replaced Insets with RectangleInsets (DG);
111  * 05-May-2005 : Removed unused draw() method (DG);
112  *
113  */

114
115 package org.jfree.chart.plot;
116
117 import java.awt.AlphaComposite JavaDoc;
118 import java.awt.BasicStroke JavaDoc;
119 import java.awt.Color JavaDoc;
120 import java.awt.Composite JavaDoc;
121 import java.awt.Font JavaDoc;
122 import java.awt.Graphics2D JavaDoc;
123 import java.awt.Image JavaDoc;
124 import java.awt.Paint JavaDoc;
125 import java.awt.Shape JavaDoc;
126 import java.awt.Stroke JavaDoc;
127 import java.awt.geom.Ellipse2D JavaDoc;
128 import java.awt.geom.Point2D JavaDoc;
129 import java.awt.geom.Rectangle2D JavaDoc;
130 import java.io.IOException JavaDoc;
131 import java.io.ObjectInputStream JavaDoc;
132 import java.io.ObjectOutputStream JavaDoc;
133 import java.io.Serializable JavaDoc;
134
135 import javax.swing.event.EventListenerList JavaDoc;
136
137 import org.jfree.chart.LegendItemCollection;
138 import org.jfree.chart.LegendItemSource;
139 import org.jfree.chart.axis.AxisLocation;
140 import org.jfree.chart.event.AxisChangeEvent;
141 import org.jfree.chart.event.AxisChangeListener;
142 import org.jfree.chart.event.ChartChangeEventType;
143 import org.jfree.chart.event.PlotChangeEvent;
144 import org.jfree.chart.event.PlotChangeListener;
145 import org.jfree.data.general.DatasetChangeEvent;
146 import org.jfree.data.general.DatasetChangeListener;
147 import org.jfree.data.general.DatasetGroup;
148 import org.jfree.io.SerialUtilities;
149 import org.jfree.text.G2TextMeasurer;
150 import org.jfree.text.TextBlock;
151 import org.jfree.text.TextBlockAnchor;
152 import org.jfree.text.TextUtilities;
153 import org.jfree.ui.Align;
154 import org.jfree.ui.RectangleEdge;
155 import org.jfree.ui.RectangleInsets;
156 import org.jfree.util.ObjectUtilities;
157 import org.jfree.util.PublicCloneable;
158
159 /**
160  * The base class for all plots in JFreeChart. The
161  * {@link org.jfree.chart.JFreeChart} class delegates the drawing of axes and
162  * data to the plot. This base class provides facilities common to most plot
163  * types.
164  */

165 public abstract class Plot implements AxisChangeListener,
166                                       DatasetChangeListener,
167                                       LegendItemSource,
168                                       PublicCloneable,
169                                       Cloneable JavaDoc,
170                                       Serializable JavaDoc {
171
172     /** For serialization. */
173     private static final long serialVersionUID = -8831571430103671324L;
174     
175     /** Useful constant representing zero. */
176     public static final Number JavaDoc ZERO = new Integer JavaDoc(0);
177
178     /** The default insets. */
179     public static final RectangleInsets DEFAULT_INSETS
180         = new RectangleInsets(4.0, 8.0, 4.0, 8.0);
181
182     /** The default outline stroke. */
183     public static final Stroke JavaDoc DEFAULT_OUTLINE_STROKE = new BasicStroke JavaDoc(0.5f);
184
185     /** The default outline color. */
186     public static final Paint JavaDoc DEFAULT_OUTLINE_PAINT = Color.gray;
187
188     /** The default foreground alpha transparency. */
189     public static final float DEFAULT_FOREGROUND_ALPHA = 1.0f;
190
191     /** The default background alpha transparency. */
192     public static final float DEFAULT_BACKGROUND_ALPHA = 1.0f;
193
194     /** The default background color. */
195     public static final Paint JavaDoc DEFAULT_BACKGROUND_PAINT = Color.white;
196
197     /** The minimum width at which the plot should be drawn. */
198     public static final int MINIMUM_WIDTH_TO_DRAW = 10;
199
200     /** The minimum height at which the plot should be drawn. */
201     public static final int MINIMUM_HEIGHT_TO_DRAW = 10;
202     
203     /** A default box shape for legend items. */
204     public static final Shape JavaDoc DEFAULT_LEGEND_ITEM_BOX
205         = new Rectangle2D.Double JavaDoc(-4.0, -4.0, 8.0, 8.0);
206     
207     /** A default circle shape for legend items. */
208     public static final Shape JavaDoc DEFAULT_LEGEND_ITEM_CIRCLE
209         = new Ellipse2D.Double JavaDoc(-4.0, -4.0, 8.0, 8.0);
210
211     /** The parent plot (<code>null</code> if this is the root plot). */
212     private Plot parent;
213
214     /** The dataset group (to be used for thread synchronisation). */
215     private DatasetGroup datasetGroup;
216
217     /** The message to display if no data is available. */
218     private String JavaDoc noDataMessage;
219
220     /** The font used to display the 'no data' message. */
221     private Font JavaDoc noDataMessageFont;
222
223     /** The paint used to draw the 'no data' message. */
224     private transient Paint JavaDoc noDataMessagePaint;
225
226     /** Amount of blank space around the plot area. */
227     private RectangleInsets insets;
228
229     /** The Stroke used to draw an outline around the plot. */
230     private transient Stroke JavaDoc outlineStroke;
231
232     /** The Paint used to draw an outline around the plot. */
233     private transient Paint JavaDoc outlinePaint;
234
235     /** An optional color used to fill the plot background. */
236     private transient Paint JavaDoc backgroundPaint;
237
238     /** An optional image for the plot background. */
239     private transient Image JavaDoc backgroundImage; // not currently serialized
240

241     /** The alignment for the background image. */
242     private int backgroundImageAlignment = Align.FIT;
243
244     /** The alpha-transparency for the plot. */
245     private float foregroundAlpha;
246
247     /** The alpha transparency for the background paint. */
248     private float backgroundAlpha;
249
250     /** The drawing supplier. */
251     private DrawingSupplier drawingSupplier;
252
253     /** Storage for registered change listeners. */
254     private transient EventListenerList JavaDoc listenerList;
255
256     /**
257      * Defines dataArea rectangle as the ratio formed from dividing height by
258      * width (of the dataArea). Modifies plot area calculations.
259      * ratio>0 will attempt to layout the plot so that the
260      * dataArea.height/dataArea.width = ratio.
261      * ratio<0 will attempt to layout the plot so that the
262      * dataArea.height/dataArea.width in plot units (not java2D units as when
263      * ratio>0) = -1.*ratio.
264      */
//dmo
265
private double dataAreaRatio = 0.0; //zero when the parameter is not set
266

267     /**
268      * Creates a new plot.
269      */

270     protected Plot() {
271
272         this.parent = null;
273         this.insets = DEFAULT_INSETS;
274         this.backgroundPaint = DEFAULT_BACKGROUND_PAINT;
275         this.backgroundAlpha = DEFAULT_BACKGROUND_ALPHA;
276         this.backgroundImage = null;
277         this.outlineStroke = DEFAULT_OUTLINE_STROKE;
278         this.outlinePaint = DEFAULT_OUTLINE_PAINT;
279         this.foregroundAlpha = DEFAULT_FOREGROUND_ALPHA;
280
281         this.noDataMessage = null;
282         this.noDataMessageFont = new Font JavaDoc("SansSerif", Font.PLAIN, 12);
283         this.noDataMessagePaint = Color.black;
284
285         this.drawingSupplier = new DefaultDrawingSupplier();
286
287         this.listenerList = new EventListenerList JavaDoc();
288
289     }
290
291     /**
292      * Returns the dataset group for the plot (not currently used).
293      *
294      * @return The dataset group.
295      */

296     public DatasetGroup getDatasetGroup() {
297         return this.datasetGroup;
298     }
299
300     /**
301      * Sets the dataset group (not currently used).
302      *
303      * @param group the dataset group (<code>null</code> permitted).
304      */

305     protected void setDatasetGroup(DatasetGroup group) {
306         this.datasetGroup = group;
307     }
308
309     /**
310      * Returns the string that is displayed when the dataset is empty or
311      * <code>null</code>.
312      *
313      * @return The 'no data' message (<code>null</code> possible).
314      */

315     public String JavaDoc getNoDataMessage() {
316         return this.noDataMessage;
317     }
318
319     /**
320      * Sets the message that is displayed when the dataset is empty or null.
321      *
322      * @param message the message (null permitted).
323      */

324     public void setNoDataMessage(String JavaDoc message) {
325         this.noDataMessage = message;
326     }
327
328     /**
329      * Returns the font used to display the 'no data' message.
330      *
331      * @return The font.
332      */

333     public Font JavaDoc getNoDataMessageFont() {
334         return this.noDataMessageFont;
335     }
336
337     /**
338      * Sets the font used to display the 'no data' message.
339      *
340      * @param font the font.
341      */

342     public void setNoDataMessageFont(Font JavaDoc font) {
343         this.noDataMessageFont = font;
344     }
345
346     /**
347      * Returns the paint used to display the 'no data' message.
348      *
349      * @return The paint.
350      */

351     public Paint JavaDoc getNoDataMessagePaint() {
352         return this.noDataMessagePaint;
353     }
354
355     /**
356      * Sets the paint used to display the 'no data' message.
357      *
358      * @param paint the paint.
359      */

360     public void setNoDataMessagePaint(Paint JavaDoc paint) {
361         this.noDataMessagePaint = paint;
362     }
363
364     /**
365      * Returns a short string describing the plot type.
366      * <P>
367      * Note: this gets used in the chart property editing user interface,
368      * but there needs to be a better mechanism for identifying the plot type.
369      *
370      * @return A short string describing the plot type.
371      */

372     public abstract String JavaDoc getPlotType();
373
374     /**
375      * Returns the parent plot (or <code>null</code> if this plot is not part
376      * of a combined plot).
377      *
378      * @return The parent plot.
379      */

380     public Plot getParent() {
381         return this.parent;
382     }
383
384     /**
385      * Sets the parent plot.
386      *
387      * @param parent the parent plot.
388      */

389     public void setParent(Plot parent) {
390         this.parent = parent;
391     }
392
393     /**
394      * Returns the root plot.
395      *
396      * @return The root plot.
397      */

398     public Plot getRootPlot() {
399
400         Plot p = getParent();
401         if (p == null) {
402             return this;
403         }
404         else {
405             return p.getRootPlot();
406         }
407
408     }
409
410     /**
411      * Returns true if this plot is part of a combined plot structure.
412      *
413      * @return <code>true</code> if this plot is part of a combined plot
414      * structure.
415      */

416     public boolean isSubplot() {
417         return (getParent() != null);
418     }
419
420     /**
421      * Returns the insets for the plot area.
422      *
423      * @return The insets (never <code>null</code>).
424      */

425     public RectangleInsets getInsets() {
426         return this.insets;
427     }
428
429     /**
430      * Sets the insets for the plot and sends a {@link PlotChangeEvent} to
431      * all registered listeners.
432      *
433      * @param insets the new insets (<code>null</code> not permitted).
434      */

435     public void setInsets(RectangleInsets insets) {
436         setInsets(insets, true);
437     }
438
439     /**
440      * Sets the insets for the plot and, if requested, and sends a
441      * {@link PlotChangeEvent} to all registered listeners.
442      *
443      * @param insets the new insets (<code>null</code> not permitted).
444      * @param notify a flag that controls whether the registered listeners are
445      * notified.
446      */

447     public void setInsets(RectangleInsets insets, boolean notify) {
448         if (insets == null) {
449             throw new IllegalArgumentException JavaDoc("Null 'insets' argument.");
450         }
451         if (!this.insets.equals(insets)) {
452             this.insets = insets;
453             if (notify) {
454                 notifyListeners(new PlotChangeEvent(this));
455             }
456         }
457
458     }
459
460     /**
461      * Returns the background color of the plot area.
462      *
463      * @return The paint (possibly <code>null</code>).
464      */

465     public Paint JavaDoc getBackgroundPaint() {
466         return this.backgroundPaint;
467     }
468
469     /**
470      * Sets the background color of the plot area and sends a
471      * {@link PlotChangeEvent} to all registered listeners.
472      *
473      * @param paint the paint (<code>null</code> permitted).
474      */

475     public void setBackgroundPaint(Paint JavaDoc paint) {
476
477         if (paint == null) {
478             if (this.backgroundPaint != null) {
479                 this.backgroundPaint = null;
480                 notifyListeners(new PlotChangeEvent(this));
481             }
482         }
483         else {
484             if (this.backgroundPaint != null) {
485                 if (this.backgroundPaint.equals(paint)) {
486                     return; // nothing to do
487
}
488             }
489             this.backgroundPaint = paint;
490             notifyListeners(new PlotChangeEvent(this));
491         }
492
493     }
494
495     /**
496      * Returns the alpha transparency of the plot area background.
497      *
498      * @return The alpha transparency.
499      */

500     public float getBackgroundAlpha() {
501         return this.backgroundAlpha;
502     }
503
504     /**
505      * Sets the alpha transparency of the plot area background, and notifies
506      * registered listeners that the plot has been modified.
507      *
508      * @param alpha the new alpha value.
509      */

510     public void setBackgroundAlpha(float alpha) {
511
512         if (this.backgroundAlpha != alpha) {
513             this.backgroundAlpha = alpha;
514             notifyListeners(new PlotChangeEvent(this));
515         }
516
517     }
518
519     /**
520      * Returns the drawing supplier for the plot.
521      *
522      * @return The drawing supplier (possibly <code>null</code>).
523      */

524     public DrawingSupplier getDrawingSupplier() {
525         DrawingSupplier result = null;
526         Plot p = getParent();
527         if (p != null) {
528             result = p.getDrawingSupplier();
529         }
530         else {
531             result = this.drawingSupplier;
532         }
533         return result;
534     }
535
536     /**
537      * Sets the drawing supplier for the plot. The drawing supplier is
538      * responsible for supplying a limitless (possibly repeating) sequence of
539      * <code>Paint</code>, <code>Stroke</code> and <code>Shape</code> objects
540      * that the plot's renderer(s) can use to populate its (their) tables.
541      *
542      * @param supplier the new supplier.
543      */

544     public void setDrawingSupplier(DrawingSupplier supplier) {
545         this.drawingSupplier = supplier;
546         notifyListeners(new PlotChangeEvent(this));
547     }
548
549     /**
550      * Returns the background image that is used to fill the plot's background
551      * area.
552      *
553      * @return The image (possibly <code>null</code>).
554      */

555     public Image JavaDoc getBackgroundImage() {
556         return this.backgroundImage;
557     }
558
559     /**
560      * Sets the background image for the plot.
561      *
562      * @param image the image (<code>null</code> permitted).
563      */

564     public void setBackgroundImage(Image JavaDoc image) {
565         this.backgroundImage = image;
566         notifyListeners(new PlotChangeEvent(this));
567     }
568
569     /**
570      * Returns the background image alignment. Alignment constants are defined
571      * in the <code>org.jfree.ui.Align</code> class in the JCommon class
572      * library.
573      *
574      * @return The alignment.
575      */

576     public int getBackgroundImageAlignment() {
577         return this.backgroundImageAlignment;
578     }
579
580     /**
581      * Sets the alignment for the background image and sends a
582      * {@link PlotChangeEvent} to all registered listeners. Alignment options
583      * are defined by the {@link org.jfree.ui.Align} class in the JCommon
584      * class library.
585      *
586      * @param alignment the alignment.
587      */

588     public void setBackgroundImageAlignment(int alignment) {
589         if (this.backgroundImageAlignment != alignment) {
590             this.backgroundImageAlignment = alignment;
591             notifyListeners(new PlotChangeEvent(this));
592         }
593     }
594
595     /**
596      * Returns the stroke used to outline the plot area.
597      *
598      * @return The stroke (possibly <code>null</code>).
599      */

600     public Stroke JavaDoc getOutlineStroke() {
601         return this.outlineStroke;
602     }
603
604     /**
605      * Sets the stroke used to outline the plot area and sends a
606      * {@link PlotChangeEvent} to all registered listeners. If you set this
607      * attribute to <code>null<.code>, no outline will be drawn.
608      *
609      * @param stroke the stroke (<code>null</code> permitted).
610      */

611     public void setOutlineStroke(Stroke JavaDoc stroke) {
612
613         if (stroke == null) {
614             if (this.outlineStroke != null) {
615                 this.outlineStroke = null;
616                 notifyListeners(new PlotChangeEvent(this));
617             }
618         }
619         else {
620             if (this.outlineStroke != null) {
621                 if (this.outlineStroke.equals(stroke)) {
622                     return; // nothing to do
623
}
624             }
625             this.outlineStroke = stroke;
626             notifyListeners(new PlotChangeEvent(this));
627         }
628
629     }
630
631     /**
632      * Returns the color used to draw the outline of the plot area.
633      *
634      * @return The color (possibly <code>null<code>).
635      */

636     public Paint JavaDoc getOutlinePaint() {
637         return this.outlinePaint;
638     }
639
640     /**
641      * Sets the paint used to draw the outline of the plot area and sends a
642      * {@link PlotChangeEvent} to all registered listeners. If you set this
643      * attribute to <code>null</code>, no outline will be drawn.
644      *
645      * @param paint the paint (<code>null</code> permitted).
646      */

647     public void setOutlinePaint(Paint JavaDoc paint) {
648
649         if (paint == null) {
650             if (this.outlinePaint != null) {
651                 this.outlinePaint = null;
652                 notifyListeners(new PlotChangeEvent(this));
653             }
654         }
655         else {
656             if (this.outlinePaint != null) {
657                 if (this.outlinePaint.equals(paint)) {
658                     return; // nothing to do
659
}
660             }
661             this.outlinePaint = paint;
662             notifyListeners(new PlotChangeEvent(this));
663         }
664
665     }
666
667     /**
668      * Returns the alpha-transparency for the plot foreground.
669      *
670      * @return The alpha-transparency.
671      */

672     public float getForegroundAlpha() {
673         return this.foregroundAlpha;
674     }
675
676     /**
677      * Sets the alpha-transparency for the plot.
678      *
679      * @param alpha the new alpha transparency.
680      */

681     public void setForegroundAlpha(float alpha) {
682
683         if (this.foregroundAlpha != alpha) {
684             this.foregroundAlpha = alpha;
685             notifyListeners(new PlotChangeEvent(this));
686         }
687
688     }
689
690     /**
691      * Returns the legend items for the plot. By default, this method returns
692      * <code>null</code>. Subclasses should override to return a
693      * {@link LegendItemCollection}.
694      *
695      * @return The legend items for the plot (possibly <code>null</code>).
696      */

697     public LegendItemCollection getLegendItems() {
698         return null;
699     }
700
701     /**
702      * Registers an object for notification of changes to the plot.
703      *
704      * @param listener the object to be registered.
705      */

706     public void addChangeListener(PlotChangeListener listener) {
707         this.listenerList.add(PlotChangeListener.class, listener);
708     }
709
710     /**
711      * Unregisters an object for notification of changes to the plot.
712      *
713      * @param listener the object to be unregistered.
714      */

715     public void removeChangeListener(PlotChangeListener listener) {
716         this.listenerList.remove(PlotChangeListener.class, listener);
717     }
718
719     /**
720      * Notifies all registered listeners that the plot has been modified.
721      *
722      * @param event information about the change event.
723      */

724     public void notifyListeners(PlotChangeEvent event) {
725
726         Object JavaDoc[] listeners = this.listenerList.getListenerList();
727         for (int i = listeners.length - 2; i >= 0; i -= 2) {
728             if (listeners[i] == PlotChangeListener.class) {
729                 ((PlotChangeListener) listeners[i + 1]).plotChanged(event);
730             }
731         }
732
733     }
734
735     /**
736      * Draws the plot within the specified area. The anchor is a point on the
737      * chart that is specified externally (for instance, it may be the last
738      * point of the last mouse click performed by the user) - plots can use or
739      * ignore this value as they see fit.
740      * <br><br>
741      * Subclasses need to provide an implementation of this method, obviously.
742      *
743      * @param g2 the graphics device.
744      * @param area the plot area.
745      * @param anchor the anchor point (<code>null</code> permitted).
746      * @param parentState the parent state (if any).
747      * @param info carries back plot rendering info.
748      */

749     public abstract void draw(Graphics2D JavaDoc g2,
750                               Rectangle2D JavaDoc area,
751                               Point2D JavaDoc anchor,
752                               PlotState parentState,
753                               PlotRenderingInfo info);
754                               
755     /**
756      * Draws the plot background (the background color and/or image).
757      * <P>
758      * This method will be called during the chart drawing process and is
759      * declared public so that it can be accessed by the renderers used by
760      * certain subclasses. You shouldn't need to call this method directly.
761      *
762      * @param g2 the graphics device.
763      * @param area the area within which the plot should be drawn.
764      */

765     public void drawBackground(Graphics2D JavaDoc g2, Rectangle2D JavaDoc area) {
766         fillBackground(g2, area);
767         drawBackgroundImage(g2, area);
768     }
769
770     /**
771      * Fills the specified area with the background paint.
772      *
773      * @param g2 the graphics device.
774      * @param area the area.
775      */

776     protected void fillBackground(Graphics2D JavaDoc g2, Rectangle2D JavaDoc area) {
777         if (this.backgroundPaint != null) {
778             Composite JavaDoc originalComposite = g2.getComposite();
779             g2.setComposite(
780                 AlphaComposite.getInstance(
781                     AlphaComposite.SRC_OVER, this.backgroundAlpha
782                 )
783             );
784             g2.setPaint(this.backgroundPaint);
785             g2.fill(area);
786             g2.setComposite(originalComposite);
787         }
788     }
789     
790     /**
791      * Draws the background image (if there is one) aligned within the
792      * specified area.
793      *
794      * @param g2 the graphics device.
795      * @param area the area.
796      */

797     protected void drawBackgroundImage(Graphics2D JavaDoc g2, Rectangle2D JavaDoc area) {
798         if (this.backgroundImage != null) {
799             Composite JavaDoc originalComposite = g2.getComposite();
800             g2.setComposite(AlphaComposite.getInstance(
801                 AlphaComposite.SRC, this.backgroundAlpha
802             ));
803             Rectangle2D JavaDoc dest = new Rectangle2D.Double JavaDoc(
804                 0.0, 0.0,
805                 this.backgroundImage.getWidth(null),
806                 this.backgroundImage.getHeight(null)
807             );
808             Align.align(dest, area, this.backgroundImageAlignment);
809             g2.drawImage(
810                 this.backgroundImage,
811                 (int) dest.getX(), (int) dest.getY(),
812                 (int) dest.getWidth() + 1, (int) dest.getHeight() + 1, null
813             );
814             g2.setComposite(originalComposite);
815         }
816     }
817     
818     /**
819      * Draws the plot outline. This method will be called during the chart
820      * drawing process and is declared public so that it can be accessed by the
821      * renderers used by certain subclasses. You shouldn't need to call this
822      * method directly.
823      *
824      * @param g2 the graphics device.
825      * @param area the area within which the plot should be drawn.
826      */

827     public void drawOutline(Graphics2D JavaDoc g2, Rectangle2D JavaDoc area) {
828         if ((this.outlineStroke != null) && (this.outlinePaint != null)) {
829             g2.setStroke(this.outlineStroke);
830             g2.setPaint(this.outlinePaint);
831             g2.draw(area);
832         }
833     }
834
835     /**
836      * Draws a message to state that there is no data to plot.
837      *
838      * @param g2 the graphics device.
839      * @param area the area within which the plot should be drawn.
840      */

841     protected void drawNoDataMessage(Graphics2D JavaDoc g2, Rectangle2D JavaDoc area) {
842
843         Shape JavaDoc savedClip = g2.getClip();
844         g2.clip(area);
845         String JavaDoc message = this.noDataMessage;
846         if (message != null) {
847             g2.setFont(this.noDataMessageFont);
848             g2.setPaint(this.noDataMessagePaint);
849             TextBlock block = TextUtilities.createTextBlock(
850                 this.noDataMessage, this.noDataMessageFont,
851                 this.noDataMessagePaint,
852                 0.9f * (float) area.getWidth(), new G2TextMeasurer(g2)
853             );
854             block.draw(
855                 g2, (float) area.getCenterX(), (float) area.getCenterY(),
856                 TextBlockAnchor.CENTER
857             );
858         }
859         g2.setClip(savedClip);
860
861     }
862
863     /**
864      * Handles a 'click' on the plot. Since the plot does not maintain any
865      * information about where it has been drawn, the plot rendering info is
866      * supplied as an argument.
867      *
868      * @param x the x coordinate (in Java2D space).
869      * @param y the y coordinate (in Java2D space).
870      * @param info an object containing information about the dimensions of
871      * the plot.
872      */

873     public void handleClick(int x, int y, PlotRenderingInfo info) {
874         // provides a 'no action' default
875
}
876
877     /**
878      * Performs a zoom on the plot. Subclasses should override if zooming is
879      * appropriate for the type of plot.
880      *
881      * @param percent the zoom percentage.
882      */

883     public void zoom(double percent) {
884         // do nothing by default.
885
}
886
887     /**
888      * Receives notification of a change to one of the plot's axes.
889      *
890      * @param event information about the event (not used here).
891      */

892     public void axisChanged(AxisChangeEvent event) {
893         notifyListeners(new PlotChangeEvent(this));
894     }
895
896     /**
897      * Receives notification of a change to the plot's dataset.
898      * <P>
899      * The plot reacts by passing on a plot change event to all registered
900      * listeners.
901      *
902      * @param event information about the event (not used here).
903      */

904     public void datasetChanged(DatasetChangeEvent event) {
905         PlotChangeEvent newEvent = new PlotChangeEvent(this);
906         newEvent.setType(ChartChangeEventType.DATASET_UPDATED);
907         notifyListeners(newEvent);
908     }
909
910     /**
911      * Adjusts the supplied x-value.
912      *
913      * @param x the x-value.
914      * @param w1 width 1.
915      * @param w2 width 2.
916      * @param edge the edge (left or right).
917      *
918      * @return The adjusted x-value.
919      */

920     protected double getRectX(double x, double w1, double w2,
921                               RectangleEdge edge) {
922
923         double result = x;
924         if (edge == RectangleEdge.LEFT) {
925             result = result + w1;
926         }
927         else if (edge == RectangleEdge.RIGHT) {
928             result = result + w2;
929         }
930         return result;
931
932     }
933
934     /**
935      * Adjusts the supplied y-value.
936      *
937      * @param y the x-value.
938      * @param h1 height 1.
939      * @param h2 height 2.
940      * @param edge the edge (top or bottom).
941      *
942      * @return The adjusted y-value.
943      */

944     protected double getRectY(double y, double h1, double h2,
945                               RectangleEdge edge) {
946
947         double result = y;
948         if (edge == RectangleEdge.TOP) {
949             result = result + h1;
950         }
951         else if (edge == RectangleEdge.BOTTOM) {
952             result = result + h2;
953         }
954         return result;
955
956     }
957
958     /**
959      * Returns the data area ratio.
960      *
961      * @return The ratio.
962      */

963     public double getDataAreaRatio() {
964         return this.dataAreaRatio;
965     }
966
967     /**
968      * Sets the data area ratio.
969      *
970      * @param ratio the ratio.
971      */

972     public void setDataAreaRatio(double ratio) {
973         this.dataAreaRatio = ratio;
974     }
975
976     /**
977      * Tests this plot for equality with another object.
978      *
979      * @param obj the object.
980      *
981      * @return <code>true</code> or <code>false</code>.
982      */

983     public boolean equals(Object JavaDoc obj) {
984
985         if (obj == this) {
986             return true;
987         }
988
989         if (!(obj instanceof Plot)) {
990             return false;
991         }
992
993         Plot that = (Plot) obj;
994
995         if (!ObjectUtilities.equal(this.noDataMessage, that.noDataMessage)) {
996             return false;
997         }
998         if (!ObjectUtilities.equal(
999             this.noDataMessageFont, that.noDataMessageFont
1000        )) {
1001            return false;
1002        }
1003        if (!ObjectUtilities.equal(
1004            this.noDataMessagePaint, that.noDataMessagePaint
1005        )) {
1006            return false;
1007        }
1008
1009        if (!ObjectUtilities.equal(this.insets, that.insets)) {
1010            return false;
1011        }
1012        if (!ObjectUtilities.equal(this.outlineStroke, that.outlineStroke)) {
1013            return false;
1014        }
1015        if (!ObjectUtilities.equal(this.outlinePaint, that.outlinePaint)) {
1016            return false;
1017        }
1018
1019        if (!ObjectUtilities.equal(
1020            this.backgroundPaint, that.backgroundPaint
1021        )) {
1022            return false;
1023        }
1024        if (!ObjectUtilities.equal(
1025            this.backgroundImage, that.backgroundImage
1026        )) {
1027            return false;
1028        }
1029        if (this.backgroundImageAlignment != that.backgroundImageAlignment) {
1030            return false;
1031        }
1032
1033        if (this.foregroundAlpha != that.foregroundAlpha) {
1034            return false;
1035        }
1036        if (this.backgroundAlpha != that.backgroundAlpha) {
1037            return false;
1038        }
1039
1040        return true;
1041
1042    }
1043
1044    /**
1045     * Creates a clone of the plot.
1046     *
1047     * @return A clone.
1048     *
1049     * @throws CloneNotSupportedException if some component of the plot does not
1050     * support cloning.
1051     */

1052    public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
1053
1054        Plot clone = (Plot) super.clone();
1055        // private Plot parent <-- don't clone the parent plot, but take care
1056
// childs in combined plots instead
1057
if (this.datasetGroup != null) {
1058            clone.datasetGroup
1059                = (DatasetGroup) ObjectUtilities.clone(this.datasetGroup);
1060        }
1061        clone.drawingSupplier
1062            = (DrawingSupplier) ObjectUtilities.clone(this.drawingSupplier);
1063        clone.listenerList = new EventListenerList JavaDoc();
1064        return clone;
1065
1066    }
1067
1068    /**
1069     * Provides serialization support.
1070     *
1071     * @param stream the output stream.
1072     *
1073     * @throws IOException if there is an I/O error.
1074     */

1075    private void writeObject(ObjectOutputStream JavaDoc stream) throws IOException JavaDoc {
1076        stream.defaultWriteObject();
1077        SerialUtilities.writePaint(this.noDataMessagePaint, stream);
1078        SerialUtilities.writeStroke(this.outlineStroke, stream);
1079        SerialUtilities.writePaint(this.outlinePaint, stream);
1080        // backgroundImage
1081
SerialUtilities.writePaint(this.backgroundPaint, stream);
1082    }
1083
1084    /**
1085     * Provides serialization support.
1086     *
1087     * @param stream the input stream.
1088     *
1089     * @throws IOException if there is an I/O error.
1090     * @throws ClassNotFoundException if there is a classpath problem.
1091     */

1092    private void readObject(ObjectInputStream JavaDoc stream)
1093        throws IOException JavaDoc, ClassNotFoundException JavaDoc {
1094        stream.defaultReadObject();
1095        this.noDataMessagePaint = SerialUtilities.readPaint(stream);
1096        this.outlineStroke = SerialUtilities.readStroke(stream);
1097        this.outlinePaint = SerialUtilities.readPaint(stream);
1098        // backgroundImage
1099
this.backgroundPaint = SerialUtilities.readPaint(stream);
1100
1101        this.listenerList = new EventListenerList JavaDoc();
1102
1103    }
1104
1105    /**
1106     * Resolves a domain axis location for a given plot orientation.
1107     *
1108     * @param location the location (<code>null</code> not permitted).
1109     * @param orientation the orientation (<code>null</code> not permitted).
1110     *
1111     * @return The edge (never <code>null</code>).
1112     */

1113    public static RectangleEdge resolveDomainAxisLocation(
1114            AxisLocation location, PlotOrientation orientation) {
1115        
1116        if (location == null) {
1117            throw new IllegalArgumentException JavaDoc("Null 'location' argument.");
1118        }
1119        if (orientation == null) {
1120            throw new IllegalArgumentException JavaDoc("Null 'orientation' argument.");
1121        }
1122
1123        RectangleEdge result = null;
1124        
1125        if (location == AxisLocation.TOP_OR_RIGHT) {
1126            if (orientation == PlotOrientation.HORIZONTAL) {
1127                result = RectangleEdge.RIGHT;
1128            }
1129            else if (orientation == PlotOrientation.VERTICAL) {
1130                result = RectangleEdge.TOP;
1131            }
1132        }
1133        else if (location == AxisLocation.TOP_OR_LEFT) {
1134            if (orientation == PlotOrientation.HORIZONTAL) {
1135                result = RectangleEdge.LEFT;
1136            }
1137            else if (orientation == PlotOrientation.VERTICAL) {
1138                result = RectangleEdge.TOP;
1139            }
1140        }
1141        else if (location == AxisLocation.BOTTOM_OR_RIGHT) {
1142            if (orientation == PlotOrientation.HORIZONTAL) {
1143                result = RectangleEdge.RIGHT;
1144            }
1145            else if (orientation == PlotOrientation.VERTICAL) {
1146                result = RectangleEdge.BOTTOM;
1147            }
1148        }
1149        else if (location == AxisLocation.BOTTOM_OR_LEFT) {
1150            if (orientation == PlotOrientation.HORIZONTAL) {
1151                result = RectangleEdge.LEFT;
1152            }
1153            else if (orientation == PlotOrientation.VERTICAL) {
1154                result = RectangleEdge.BOTTOM;
1155            }
1156        }
1157        // the above should cover all the options...
1158
if (result == null) {
1159            throw new IllegalStateException JavaDoc("resolveDomainAxisLocation()");
1160        }
1161        return result;
1162        
1163    }
1164
1165    /**
1166     * Resolves a range axis location for a given plot orientation.
1167     *
1168     * @param location the location (<code>null</code> not permitted).
1169     * @param orientation the orientation (<code>null</code> not permitted).
1170     *
1171     * @return The edge (never <code>null</code>).
1172     */

1173    public static RectangleEdge resolveRangeAxisLocation(
1174            AxisLocation location, PlotOrientation orientation) {
1175
1176        if (location == null) {
1177            throw new IllegalArgumentException JavaDoc("Null 'location' argument.");
1178        }
1179        if (orientation == null) {
1180            throw new IllegalArgumentException JavaDoc("Null 'orientation' argument.");
1181        }
1182
1183        RectangleEdge result = null;
1184        
1185        if (location == AxisLocation.TOP_OR_RIGHT) {
1186            if (orientation == PlotOrientation.HORIZONTAL) {
1187                result = RectangleEdge.TOP;
1188            }
1189            else if (orientation == PlotOrientation.VERTICAL) {
1190                result = RectangleEdge.RIGHT;
1191            }
1192        }
1193        else if (location == AxisLocation.TOP_OR_LEFT) {
1194            if (orientation == PlotOrientation.HORIZONTAL) {
1195                result = RectangleEdge.TOP;
1196            }
1197            else if (orientation == PlotOrientation.VERTICAL) {
1198                result = RectangleEdge.LEFT;
1199            }
1200        }
1201        else if (location == AxisLocation.BOTTOM_OR_RIGHT) {
1202            if (orientation == PlotOrientation.HORIZONTAL) {
1203                result = RectangleEdge.BOTTOM;
1204            }
1205            else if (orientation == PlotOrientation.VERTICAL) {
1206                result = RectangleEdge.RIGHT;
1207            }
1208        }
1209        else if (location == AxisLocation.BOTTOM_OR_LEFT) {
1210            if (orientation == PlotOrientation.HORIZONTAL) {
1211                result = RectangleEdge.BOTTOM;
1212            }
1213            else if (orientation == PlotOrientation.VERTICAL) {
1214                result = RectangleEdge.LEFT;
1215            }
1216        }
1217
1218        // the above should cover all the options...
1219
if (result == null) {
1220            throw new IllegalStateException JavaDoc("resolveRangeAxisLocation()");
1221        }
1222        return result;
1223        
1224    }
1225
1226}
1227
1228
Popular Tags