KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > ChartPanel


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  * ChartPanel.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): Andrzej Porebski;
33  * S???ren Caspersen;
34  * Jonathan Nash;
35  * Hans-Jurgen Greiner;
36  * Andreas Schneider;
37  * Daniel van Enckevort;
38  * David M O'Donnell;
39  * Arnaud Lelievre;
40  * Matthias Rose;
41  * Onno vd Akker;
42  *
43  * $Id: ChartPanel.java,v 1.20 2005/06/02 08:36:23 mungady Exp $
44  *
45  * Changes (from 28-Jun-2001)
46  * --------------------------
47  * 28-Jun-2001 : Integrated buffering code contributed by S???ren
48  * Caspersen (DG);
49  * 18-Sep-2001 : Updated header and fixed DOS encoding problem (DG);
50  * 22-Nov-2001 : Added scaling to improve display of charts in small sizes (DG);
51  * 26-Nov-2001 : Added property editing, saving and printing (DG);
52  * 11-Dec-2001 : Transferred saveChartAsPNG method to new ChartUtilities
53  * class (DG);
54  * 13-Dec-2001 : Added tooltips (DG);
55  * 16-Jan-2002 : Added an optional crosshair, based on the implementation by
56  * Jonathan Nash. Renamed the tooltips class (DG);
57  * 23-Jan-2002 : Implemented zooming based on code by Hans-Jurgen Greiner (DG);
58  * 05-Feb-2002 : Improved tooltips setup. Renamed method attemptSaveAs()
59  * --> doSaveAs() and made it public rather than private (DG);
60  * 28-Mar-2002 : Added a new constructor (DG);
61  * 09-Apr-2002 : Changed initialisation of tooltip generation, as suggested by
62  * Hans-Jurgen Greiner (DG);
63  * 27-May-2002 : New interactive zooming methods based on code by Hans-Jurgen
64  * Greiner. Renamed JFreeChartPanel --> ChartPanel, moved
65  * constants to ChartPanelConstants interface (DG);
66  * 31-May-2002 : Fixed a bug with interactive zooming and added a way to
67  * control if the zoom rectangle is filled in or drawn as an
68  * outline. A mouse drag gesture towards the top left now causes
69  * an autoRangeBoth() and is a way to undo zooms (AS);
70  * 11-Jun-2002 : Reinstated handleClick method call in mouseClicked() to get
71  * crosshairs working again (DG);
72  * 13-Jun-2002 : Added check for null popup menu in mouseDragged method (DG);
73  * 18-Jun-2002 : Added get/set methods for minimum and maximum chart
74  * dimensions (DG);
75  * 25-Jun-2002 : Removed redundant code (DG);
76  * 27-Aug-2002 : Added get/set methods for popup menu (DG);
77  * 26-Sep-2002 : Fixed errors reported by Checkstyle (DG);
78  * 22-Oct-2002 : Added translation methods for screen <--> Java2D, contributed
79  * by Daniel van Enckevort (DG);
80  * 05-Nov-2002 : Added a chart reference to the ChartMouseEvent class (DG);
81  * 22-Nov-2002 : Added test in zoom method for inverted axes, supplied by
82  * David M O'Donnell (DG);
83  * 14-Jan-2003 : Implemented ChartProgressListener interface (DG);
84  * 14-Feb-2003 : Removed deprecated setGenerateTooltips method (DG);
85  * 12-Mar-2003 : Added option to enforce filename extension (see bug id
86  * 643173) (DG);
87  * 08-Sep-2003 : Added internationalization via use of properties
88  * resourceBundle (RFE 690236) (AL);
89  * 18-Sep-2003 : Added getScaleX() and getScaleY() methods (protected) as
90  * requested by Irv Thomae (DG);
91  * 12-Nov-2003 : Added zooming support for the FastScatterPlot class (DG);
92  * 24-Nov-2003 : Minor Javadoc updates (DG);
93  * 04-Dec-2003 : Added anchor point for crosshair calculation (DG);
94  * 17-Jan-2004 : Added new methods to set tooltip delays to be used in this
95  * chart panel. Refer to patch 877565 (MR);
96  * 02-Feb-2004 : Fixed bug in zooming trigger and added zoomTriggerDistance
97  * attribute (DG);
98  * 08-Apr-2004 : Changed getScaleX() and getScaleY() from protected to
99  * public (DG);
100  * 15-Apr-2004 : Added zoomOutFactor and zoomInFactor (DG);
101  * 21-Apr-2004 : Fixed zooming bug in mouseReleased() method (DG);
102  * 13-Jul-2004 : Added check for null chart (DG);
103  * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
104  * 11-Nov-2004 : Moved constants back in from ChartPanelConstants (DG);
105  * 12-Nov-2004 : Modified zooming mechanism to support zooming within
106  * subplots (DG);
107  * 26-Jan-2005 : Fixed mouse zooming for horizontal category plots (DG);
108  * 11-Apr-2005 : Added getFillZoomRectangle() method, renamed
109  * setHorizontalZoom() --> setDomainZoomable(),
110  * setVerticalZoom() --> setRangeZoomable(), added
111  * isDomainZoomable() and isRangeZoomable(), added
112  * getHorizontalAxisTrace() and getVerticalAxisTrace(),
113  * renamed autoRangeBoth() --> restoreAutoBounds(),
114  * autoRangeHorizontal() --> restoreAutoDomainBounds(),
115  * autoRangeVertical() --> restoreAutoRangeBounds() (DG);
116  * 12-Apr-2005 : Removed working areas, added getAnchorPoint() method,
117  * added protected accessors for tracelines (DG);
118  * 18-Apr-2005 : Made constants final (DG);
119  * 26-Apr-2005 : Removed LOGGER (DG);
120  * 01-Jun-2005 : Fixed zooming for combined plots - see bug report
121  * 1212039, fix thanks to Onno vd Akker (DG);
122  */

123
124 package org.jfree.chart;
125
126 import java.awt.AWTEvent JavaDoc;
127 import java.awt.Dimension JavaDoc;
128 import java.awt.Graphics JavaDoc;
129 import java.awt.Graphics2D JavaDoc;
130 import java.awt.Image JavaDoc;
131 import java.awt.Insets JavaDoc;
132 import java.awt.Point JavaDoc;
133 import java.awt.event.ActionEvent JavaDoc;
134 import java.awt.event.ActionListener JavaDoc;
135 import java.awt.event.MouseEvent JavaDoc;
136 import java.awt.event.MouseListener JavaDoc;
137 import java.awt.event.MouseMotionListener JavaDoc;
138 import java.awt.geom.AffineTransform JavaDoc;
139 import java.awt.geom.Line2D JavaDoc;
140 import java.awt.geom.Point2D JavaDoc;
141 import java.awt.geom.Rectangle2D JavaDoc;
142 import java.awt.print.PageFormat JavaDoc;
143 import java.awt.print.Printable JavaDoc;
144 import java.awt.print.PrinterException JavaDoc;
145 import java.awt.print.PrinterJob JavaDoc;
146 import java.io.File JavaDoc;
147 import java.io.IOException JavaDoc;
148 import java.io.Serializable JavaDoc;
149 import java.util.Iterator JavaDoc;
150 import java.util.List JavaDoc;
151 import java.util.ResourceBundle JavaDoc;
152
153 import javax.swing.JFileChooser JavaDoc;
154 import javax.swing.JMenu JavaDoc;
155 import javax.swing.JMenuItem JavaDoc;
156 import javax.swing.JOptionPane JavaDoc;
157 import javax.swing.JPanel JavaDoc;
158 import javax.swing.JPopupMenu JavaDoc;
159 import javax.swing.ToolTipManager JavaDoc;
160
161 import org.jfree.chart.entity.ChartEntity;
162 import org.jfree.chart.entity.EntityCollection;
163 import org.jfree.chart.event.ChartChangeEvent;
164 import org.jfree.chart.event.ChartChangeListener;
165 import org.jfree.chart.event.ChartProgressEvent;
166 import org.jfree.chart.event.ChartProgressListener;
167 import org.jfree.chart.plot.Plot;
168 import org.jfree.chart.plot.PlotOrientation;
169 import org.jfree.chart.plot.PlotRenderingInfo;
170 import org.jfree.chart.plot.ValueAxisPlot;
171 import org.jfree.chart.plot.Zoomable;
172 import org.jfree.chart.ui.ChartPropertyEditPanel;
173 import org.jfree.ui.ExtensionFileFilter;
174
175 /**
176  * A Swing GUI component for displaying a {@link JFreeChart} object.
177  * <P>
178  * The panel registers with the chart to receive notification of changes to any
179  * component of the chart. The chart is redrawn automatically whenever this
180  * notification is received.
181  */

182 public class ChartPanel extends JPanel JavaDoc
183                         implements ChartChangeListener,
184                                    ChartProgressListener,
185                                    ActionListener JavaDoc,
186                                    MouseListener JavaDoc,
187                                    MouseMotionListener JavaDoc,
188                                    Printable JavaDoc,
189                                    Serializable JavaDoc {
190
191     /** For serialization. */
192     private static final long serialVersionUID = 6046366297214274674L;
193     
194     /** Default setting for buffer usage. */
195     public static final boolean DEFAULT_BUFFER_USED = false;
196
197     /** The default panel width. */
198     public static final int DEFAULT_WIDTH = 680;
199
200     /** The default panel height. */
201     public static final int DEFAULT_HEIGHT = 420;
202
203     /** The default limit below which chart scaling kicks in. */
204     public static final int DEFAULT_MINIMUM_DRAW_WIDTH = 300;
205
206     /** The default limit below which chart scaling kicks in. */
207     public static final int DEFAULT_MINIMUM_DRAW_HEIGHT = 200;
208
209     /** The default limit below which chart scaling kicks in. */
210     public static final int DEFAULT_MAXIMUM_DRAW_WIDTH = 800;
211
212     /** The default limit below which chart scaling kicks in. */
213     public static final int DEFAULT_MAXIMUM_DRAW_HEIGHT = 600;
214
215     /** The minimum size required to perform a zoom on a rectangle */
216     public static final int DEFAULT_ZOOM_TRIGGER_DISTANCE = 10;
217
218     /** Properties action command. */
219     public static final String JavaDoc PROPERTIES_COMMAND = "PROPERTIES";
220
221     /** Save action command. */
222     public static final String JavaDoc SAVE_COMMAND = "SAVE";
223
224     /** Print action command. */
225     public static final String JavaDoc PRINT_COMMAND = "PRINT";
226
227     /** Zoom in (both axes) action command. */
228     public static final String JavaDoc ZOOM_IN_BOTH_COMMAND = "ZOOM_IN_BOTH";
229
230     /** Zoom in (domain axis only) action command. */
231     public static final String JavaDoc ZOOM_IN_DOMAIN_COMMAND = "ZOOM_IN_DOMAIN";
232
233     /** Zoom in (range axis only) action command. */
234     public static final String JavaDoc ZOOM_IN_RANGE_COMMAND = "ZOOM_IN_RANGE";
235
236     /** Zoom out (both axes) action command. */
237     public static final String JavaDoc ZOOM_OUT_BOTH_COMMAND = "ZOOM_OUT_BOTH";
238
239     /** Zoom out (domain axis only) action command. */
240     public static final String JavaDoc ZOOM_OUT_DOMAIN_COMMAND = "ZOOM_DOMAIN_BOTH";
241
242     /** Zoom out (range axis only) action command. */
243     public static final String JavaDoc ZOOM_OUT_RANGE_COMMAND = "ZOOM_RANGE_BOTH";
244
245     /** Zoom reset (both axes) action command. */
246     public static final String JavaDoc ZOOM_RESET_BOTH_COMMAND = "ZOOM_RESET_BOTH";
247
248     /** Zoom reset (domain axis only) action command. */
249     public static final String JavaDoc ZOOM_RESET_DOMAIN_COMMAND = "ZOOM_RESET_DOMAIN";
250
251     /** Zoom reset (range axis only) action command. */
252     public static final String JavaDoc ZOOM_RESET_RANGE_COMMAND = "ZOOM_RESET_RANGE";
253
254     /** The chart that is displayed in the panel. */
255     private JFreeChart chart;
256
257     /** Storage for registered (chart) mouse listeners. */
258     private List JavaDoc chartMouseListeners;
259
260     /** A flag that controls whether or not the off-screen buffer is used. */
261     private boolean useBuffer;
262
263     /** A flag that indicates that the buffer should be refreshed. */
264     private boolean refreshBuffer;
265
266     /** A buffer for the rendered chart. */
267     private Image JavaDoc chartBuffer;
268
269     /** The height of the chart buffer. */
270     private int chartBufferHeight;
271
272     /** The width of the chart buffer. */
273     private int chartBufferWidth;
274
275     /**
276      * The minimum width for drawing a chart (uses scaling for smaller widths).
277      */

278     private int minimumDrawWidth;
279
280     /**
281      * The minimum height for drawing a chart (uses scaling for smaller
282      * heights).
283      */

284     private int minimumDrawHeight;
285
286     /**
287      * The maximum width for drawing a chart (uses scaling for bigger
288      * widths).
289      */

290     private int maximumDrawWidth;
291
292     /**
293      * The maximum height for drawing a chart (uses scaling for bigger
294      * heights).
295      */

296     private int maximumDrawHeight;
297
298     /** The popup menu for the frame. */
299     private JPopupMenu JavaDoc popup;
300
301     /** The drawing info collected the last time the chart was drawn. */
302     private ChartRenderingInfo info;
303     
304     /** The chart anchor point. */
305     private Point2D JavaDoc anchor;
306
307     /** The scale factor used to draw the chart. */
308     private double scaleX;
309
310     /** The scale factor used to draw the chart. */
311     private double scaleY;
312
313     /** The plot orientation. */
314     private PlotOrientation orientation = PlotOrientation.VERTICAL;
315     
316     /** A flag that controls whether or not domain zooming is enabled. */
317     private boolean domainZoomable = false;
318
319     /** A flag that controls whether or not range zooming is enabled. */
320     private boolean rangeZoomable = false;
321
322     /**
323      * The zoom rectangle starting point (selected by the user with a mouse
324      * click). This is a point on the screen, not the chart (which may have
325      * been scaled up or down to fit the panel).
326      */

327     private Point JavaDoc zoomPoint = null;
328
329     /** The zoom rectangle (selected by the user with the mouse). */
330     private transient Rectangle2D JavaDoc zoomRectangle = null;
331
332     /** Controls if the zoom rectangle is drawn as an outline or filled. */
333     private boolean fillZoomRectangle = false;
334
335     /** The minimum distance required to drag the mouse to trigger a zoom. */
336     private int zoomTriggerDistance;
337     
338     /** A flag that controls whether or not horizontal tracing is enabled. */
339     private boolean horizontalAxisTrace = false;
340
341     /** A flag that controls whether or not vertical tracing is enabled. */
342     private boolean verticalAxisTrace = false;
343
344     /** A vertical trace line. */
345     private transient Line2D JavaDoc verticalTraceLine;
346
347     /** A horizontal trace line. */
348     private transient Line2D JavaDoc horizontalTraceLine;
349
350     /** Menu item for zooming in on a chart (both axes). */
351     private JMenuItem JavaDoc zoomInBothMenuItem;
352
353     /** Menu item for zooming in on a chart (domain axis). */
354     private JMenuItem JavaDoc zoomInDomainMenuItem;
355
356     /** Menu item for zooming in on a chart (range axis). */
357     private JMenuItem JavaDoc zoomInRangeMenuItem;
358
359     /** Menu item for zooming out on a chart. */
360     private JMenuItem JavaDoc zoomOutBothMenuItem;
361
362     /** Menu item for zooming out on a chart (domain axis). */
363     private JMenuItem JavaDoc zoomOutDomainMenuItem;
364
365     /** Menu item for zooming out on a chart (range axis). */
366     private JMenuItem JavaDoc zoomOutRangeMenuItem;
367
368     /** Menu item for resetting the zoom (both axes). */
369     private JMenuItem JavaDoc zoomResetBothMenuItem;
370
371     /** Menu item for resetting the zoom (domain axis only). */
372     private JMenuItem JavaDoc zoomResetDomainMenuItem;
373
374     /** Menu item for resetting the zoom (range axis only). */
375     private JMenuItem JavaDoc zoomResetRangeMenuItem;
376
377     /** A flag that controls whether or not file extensions are enforced. */
378     private boolean enforceFileExtensions;
379
380     /** A flag that indicates if original tooltip delays are changed. */
381     private boolean ownToolTipDelaysActive;
382     
383     /** Original initial tooltip delay of ToolTipManager.sharedInstance(). */
384     private int originalToolTipInitialDelay;
385
386     /** Original reshow tooltip delay of ToolTipManager.sharedInstance(). */
387     private int originalToolTipReshowDelay;
388
389     /** Original dismiss tooltip delay of ToolTipManager.sharedInstance(). */
390     private int originalToolTipDismissDelay;
391
392     /** Own initial tooltip delay to be used in this chart panel. */
393     private int ownToolTipInitialDelay;
394     
395     /** Own reshow tooltip delay to be used in this chart panel. */
396     private int ownToolTipReshowDelay;
397
398     /** Own dismiss tooltip delay to be used in this chart panel. */
399     private int ownToolTipDismissDelay;
400
401     /** The factor used to zoom in on an axis range. */
402     private double zoomInFactor = 0.5;
403     
404     /** The factor used to zoom out on an axis range. */
405     private double zoomOutFactor = 2.0;
406     
407     /** The resourceBundle for the localization. */
408     protected static ResourceBundle JavaDoc localizationResources
409         = ResourceBundle.getBundle("org.jfree.chart.LocalizationBundle");
410
411     /**
412      * Constructs a panel that displays the specified chart.
413      *
414      * @param chart the chart.
415      */

416     public ChartPanel(JFreeChart chart) {
417
418         this(
419             chart,
420             DEFAULT_WIDTH,
421             DEFAULT_HEIGHT,
422             DEFAULT_MINIMUM_DRAW_WIDTH,
423             DEFAULT_MINIMUM_DRAW_HEIGHT,
424             DEFAULT_MAXIMUM_DRAW_WIDTH,
425             DEFAULT_MAXIMUM_DRAW_HEIGHT,
426             DEFAULT_BUFFER_USED,
427             true, // properties
428
true, // save
429
true, // print
430
true, // zoom
431
true // tooltips
432
);
433
434     }
435
436     /**
437      * Constructs a panel containing a chart.
438      *
439      * @param chart the chart.
440      * @param useBuffer a flag controlling whether or not an off-screen buffer
441      * is used.
442      */

443     public ChartPanel(JFreeChart chart, boolean useBuffer) {
444
445         this(chart,
446              DEFAULT_WIDTH,
447              DEFAULT_HEIGHT,
448              DEFAULT_MINIMUM_DRAW_WIDTH,
449              DEFAULT_MINIMUM_DRAW_HEIGHT,
450              DEFAULT_MAXIMUM_DRAW_WIDTH,
451              DEFAULT_MAXIMUM_DRAW_HEIGHT,
452              useBuffer,
453              true, // properties
454
true, // save
455
true, // print
456
true, // zoom
457
true // tooltips
458
);
459
460     }
461
462     /**
463      * Constructs a JFreeChart panel.
464      *
465      * @param chart the chart.
466      * @param properties a flag indicating whether or not the chart property
467      * editor should be available via the popup menu.
468      * @param save a flag indicating whether or not save options should be
469      * available via the popup menu.
470      * @param print a flag indicating whether or not the print option
471      * should be available via the popup menu.
472      * @param zoom a flag indicating whether or not zoom options should
473      * be added to the popup menu.
474      * @param tooltips a flag indicating whether or not tooltips should be
475      * enabled for the chart.
476      */

477     public ChartPanel(JFreeChart chart,
478                       boolean properties,
479                       boolean save,
480                       boolean print,
481                       boolean zoom,
482                       boolean tooltips) {
483
484         this(chart,
485              DEFAULT_WIDTH,
486              DEFAULT_HEIGHT,
487              DEFAULT_MINIMUM_DRAW_WIDTH,
488              DEFAULT_MINIMUM_DRAW_HEIGHT,
489              DEFAULT_MAXIMUM_DRAW_WIDTH,
490              DEFAULT_MAXIMUM_DRAW_HEIGHT,
491              DEFAULT_BUFFER_USED,
492              properties,
493              save,
494              print,
495              zoom,
496              tooltips
497              );
498
499     }
500
501     /**
502      * Constructs a JFreeChart panel.
503      *
504      * @param chart the chart.
505      * @param width the preferred width of the panel.
506      * @param height the preferred height of the panel.
507      * @param minimumDrawWidth the minimum drawing width.
508      * @param minimumDrawHeight the minimum drawing height.
509      * @param maximumDrawWidth the maximum drawing width.
510      * @param maximumDrawHeight the maximum drawing height.
511      * @param useBuffer a flag that indicates whether to use the off-screen
512      * buffer to improve performance (at the expense of
513      * memory).
514      * @param properties a flag indicating whether or not the chart property
515      * editor should be available via the popup menu.
516      * @param save a flag indicating whether or not save options should be
517      * available via the popup menu.
518      * @param print a flag indicating whether or not the print option
519      * should be available via the popup menu.
520      * @param zoom a flag indicating whether or not zoom options should be
521      * added to the popup menu.
522      * @param tooltips a flag indicating whether or not tooltips should be
523      * enabled for the chart.
524      */

525     public ChartPanel(JFreeChart chart,
526                       int width,
527                       int height,
528                       int minimumDrawWidth,
529                       int minimumDrawHeight,
530                       int maximumDrawWidth,
531                       int maximumDrawHeight,
532                       boolean useBuffer,
533                       boolean properties,
534                       boolean save,
535                       boolean print,
536                       boolean zoom,
537                       boolean tooltips) {
538
539         this.chart = chart;
540         this.chartMouseListeners = new java.util.ArrayList JavaDoc();
541         if (chart != null) {
542             chart.addChangeListener(this);
543             Plot plot = chart.getPlot();
544             this.domainZoomable = false;
545             this.rangeZoomable = false;
546             if (plot instanceof Zoomable) {
547                 Zoomable z = (Zoomable) plot;
548                 this.domainZoomable = z.isDomainZoomable();
549                 this.rangeZoomable = z.isRangeZoomable();
550                 this.orientation = z.getOrientation();
551             }
552         }
553         this.info = new ChartRenderingInfo();
554         setPreferredSize(new Dimension JavaDoc(width, height));
555         this.useBuffer = useBuffer;
556         this.refreshBuffer = false;
557         this.minimumDrawWidth = minimumDrawWidth;
558         this.minimumDrawHeight = minimumDrawHeight;
559         this.maximumDrawWidth = maximumDrawWidth;
560         this.maximumDrawHeight = maximumDrawHeight;
561         this.zoomTriggerDistance = DEFAULT_ZOOM_TRIGGER_DISTANCE;
562
563         // set up popup menu...
564
this.popup = null;
565         if (properties || save || print || zoom) {
566             this.popup = createPopupMenu(properties, save, print, zoom);
567         }
568
569         enableEvents(AWTEvent.MOUSE_EVENT_MASK);
570         enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
571         setDisplayToolTips(tooltips);
572         addMouseListener(this);
573         addMouseMotionListener(this);
574
575         this.enforceFileExtensions = true;
576
577         // initialize ChartPanel-specific tool tip delays with
578
// values the from ToolTipManager.sharedInstance()
579
ToolTipManager JavaDoc ttm = ToolTipManager.sharedInstance();
580         this.ownToolTipInitialDelay = ttm.getInitialDelay();
581         this.ownToolTipDismissDelay = ttm.getDismissDelay();
582         this.ownToolTipReshowDelay = ttm.getReshowDelay();
583
584     }
585
586     /**
587      * Returns the chart contained in the panel.
588      *
589      * @return The chart (possibly <code>null</code>).
590      */

591     public JFreeChart getChart() {
592         return this.chart;
593     }
594
595     /**
596      * Sets the chart that is displayed in the panel.
597      *
598      * @param chart the chart (<code>null</code> permitted).
599      */

600     public void setChart(JFreeChart chart) {
601
602         // stop listening for changes to the existing chart
603
if (this.chart != null) {
604             this.chart.removeChangeListener(this);
605             this.chart.removeProgressListener(this);
606         }
607
608         // add the new chart
609
this.chart = chart;
610         if (chart != null) {
611             this.chart.addChangeListener(this);
612             this.chart.addProgressListener(this);
613             Plot plot = chart.getPlot();
614             this.domainZoomable = false;
615             this.rangeZoomable = false;
616             if (plot instanceof Zoomable) {
617                 Zoomable z = (Zoomable) plot;
618                 this.domainZoomable = z.isDomainZoomable();
619                 this.rangeZoomable = z.isRangeZoomable();
620                 this.orientation = z.getOrientation();
621             }
622         }
623         else {
624             this.domainZoomable = false;
625             this.rangeZoomable = false;
626         }
627         if (this.useBuffer) {
628             this.refreshBuffer = true;
629         }
630         repaint();
631
632     }
633
634     /**
635      * Returns the minimum drawing width for charts.
636      * <P>
637      * If the width available on the panel is less than this, then the chart is
638      * drawn at the minimum width then scaled down to fit.
639      *
640      * @return The minimum drawing width.
641      */

642     public int getMinimumDrawWidth() {
643         return this.minimumDrawWidth;
644     }
645
646     /**
647      * Sets the minimum drawing width for the chart on this panel.
648      * <P>
649      * At the time the chart is drawn on the panel, if the available width is
650      * less than this amount, the chart will be drawn using the minimum width
651      * then scaled down to fit the available space.
652      *
653      * @param width The width.
654      */

655     public void setMinimumDrawWidth(int width) {
656         this.minimumDrawWidth = width;
657     }
658
659     /**
660      * Returns the maximum drawing width for charts.
661      * <P>
662      * If the width available on the panel is greater than this, then the chart
663      * is drawn at the maximum width then scaled up to fit.
664      *
665      * @return The maximum drawing width.
666      */

667     public int getMaximumDrawWidth() {
668         return this.maximumDrawWidth;
669     }
670
671     /**
672      * Sets the maximum drawing width for the chart on this panel.
673      * <P>
674      * At the time the chart is drawn on the panel, if the available width is
675      * greater than this amount, the chart will be drawn using the maximum
676      * width then scaled up to fit the available space.
677      *
678      * @param width The width.
679      */

680     public void setMaximumDrawWidth(int width) {
681         this.maximumDrawWidth = width;
682     }
683
684     /**
685      * Returns the minimum drawing height for charts.
686      * <P>
687      * If the height available on the panel is less than this, then the chart
688      * is drawn at the minimum height then scaled down to fit.
689      *
690      * @return The minimum drawing height.
691      */

692     public int getMinimumDrawHeight() {
693         return this.minimumDrawHeight;
694     }
695
696     /**
697      * Sets the minimum drawing height for the chart on this panel.
698      * <P>
699      * At the time the chart is drawn on the panel, if the available height is
700      * less than this amount, the chart will be drawn using the minimum height
701      * then scaled down to fit the available space.
702      *
703      * @param height The height.
704      */

705     public void setMinimumDrawHeight(int height) {
706         this.minimumDrawHeight = height;
707     }
708
709     /**
710      * Returns the maximum drawing height for charts.
711      * <P>
712      * If the height available on the panel is greater than this, then the
713      * chart is drawn at the maximum height then scaled up to fit.
714      *
715      * @return The maximum drawing height.
716      */

717     public int getMaximumDrawHeight() {
718         return this.maximumDrawHeight;
719     }
720
721     /**
722      * Sets the maximum drawing height for the chart on this panel.
723      * <P>
724      * At the time the chart is drawn on the panel, if the available height is
725      * greater than this amount, the chart will be drawn using the maximum
726      * height then scaled up to fit the available space.
727      *
728      * @param height The height.
729      */

730     public void setMaximumDrawHeight(int height) {
731         this.maximumDrawHeight = height;
732     }
733
734     /**
735      * Returns the X scale factor for the chart. This will be 1.0 if no
736      * scaling has been used.
737      *
738      * @return The scale factor.
739      */

740     public double getScaleX() {
741         return this.scaleX;
742     }
743     
744     /**
745      * Returns the Y scale factory for the chart. This will be 1.0 if no
746      * scaling has been used.
747      *
748      * @return The scale factor.
749      */

750     public double getScaleY() {
751         return this.scaleY;
752     }
753     
754     /**
755      * Returns the anchor point.
756      *
757      * @return The anchor point (possibly <code>null</code>).
758      */

759     public Point2D JavaDoc getAnchor() {
760         return this.anchor;
761     }
762     
763     /**
764      * Sets the anchor point. This method is provided for the use of
765      * subclasses, not end users.
766      *
767      * @param anchor the anchor point (<code>null</code> permitted).
768      */

769     protected void setAnchor(Point2D JavaDoc anchor) {
770         this.anchor = anchor;
771     }
772     
773     /**
774      * Returns the popup menu.
775      *
776      * @return The popup menu.
777      */

778     public JPopupMenu JavaDoc getPopupMenu() {
779         return this.popup;
780     }
781
782     /**
783      * Sets the popup menu for the panel.
784      *
785      * @param popup the popup menu (<code>null</code> permitted).
786      */

787     public void setPopupMenu(JPopupMenu JavaDoc popup) {
788         this.popup = popup;
789     }
790
791     /**
792      * Returns the chart rendering info from the most recent chart redraw.
793      *
794      * @return The chart rendering info.
795      */

796     public ChartRenderingInfo getChartRenderingInfo() {
797         return this.info;
798     }
799
800     /**
801      * A convenience method that switches on mouse-based zooming.
802      *
803      * @param flag <code>true</code> enables zooming and rectangle fill on
804      * zoom.
805      */

806     public void setMouseZoomable(boolean flag) {
807         setMouseZoomable(flag, true);
808     }
809
810     /**
811      * A convenience method that switches on mouse-based zooming.
812      *
813      * @param flag <code>true</code> if zooming enabled
814      * @param fillRectangle <code>true</code> if zoom rectangle is filled,
815      * false if rectangle is shown as outline only.
816      */

817     public void setMouseZoomable(boolean flag, boolean fillRectangle) {
818         setDomainZoomable(flag);
819         setRangeZoomable(flag);
820         setFillZoomRectangle(fillRectangle);
821     }
822
823     /**
824      * Returns the flag that determines whether or not zooming is enabled for
825      * the domain axis.
826      *
827      * @return A boolean.
828      */

829     public boolean isDomainZoomable() {
830         return this.domainZoomable;
831     }
832     
833     /**
834      * Sets the flag that controls whether or not zooming is enable for the
835      * domain axis. A check is made to ensure that the current plot supports
836      * zooming for the domain values.
837      *
838      * @param flag <code>true</code> enables zooming if possible.
839      */

840     public void setDomainZoomable(boolean flag) {
841         if (flag) {
842             Plot plot = this.chart.getPlot();
843             if (plot instanceof Zoomable) {
844                 Zoomable z = (Zoomable) plot;
845                 this.domainZoomable = flag && (z.isDomainZoomable());
846             }
847         }
848         else {
849             this.domainZoomable = false;
850         }
851     }
852
853     /**
854      * Returns the flag that determines whether or not zooming is enabled for
855      * the range axis.
856      *
857      * @return A boolean.
858      */

859     public boolean isRangeZoomable() {
860         return this.rangeZoomable;
861     }
862     
863     /**
864      * A flag that controls mouse-based zooming on the vertical axis.
865      *
866      * @param flag <code>true</code> enables zooming.
867      */

868     public void setRangeZoomable(boolean flag) {
869         if (flag) {
870             Plot plot = this.chart.getPlot();
871             if (plot instanceof Zoomable) {
872                 Zoomable z = (Zoomable) plot;
873                 this.rangeZoomable = flag && (z.isRangeZoomable());
874             }
875         }
876         else {
877             this.rangeZoomable = false;
878         }
879     }
880
881     /**
882      * Returns the flag that controls whether or not the zoom rectangle is
883      * filled when drawn.
884      *
885      * @return A boolean.
886      */

887     public boolean getFillZoomRectangle() {
888         return this.fillZoomRectangle;
889     }
890     
891     /**
892      * A flag that controls how the zoom rectangle is drawn.
893      *
894      * @param flag <code>true</code> instructs to fill the rectangle on
895      * zoom, otherwise it will be outlined.
896      */

897     public void setFillZoomRectangle(boolean flag) {
898         this.fillZoomRectangle = flag;
899     }
900
901     /**
902      * Returns the zoom trigger distance. This controls how far the mouse must
903      * move before a zoom action is triggered.
904      *
905      * @return The distance (in Java2D units).
906      */

907     public int getZoomTriggerDistance() {
908         return this.zoomTriggerDistance;
909     }
910     
911     /**
912      * Sets the zoom trigger distance. This controls how far the mouse must
913      * move before a zoom action is triggered.
914      *
915      * @param distance the distance (in Java2D units).
916      */

917     public void setZoomTriggerDistance(int distance) {
918         this.zoomTriggerDistance = distance;
919     }
920     
921     /**
922      * Returns the flag that controls whether or not a horizontal axis trace
923      * line is drawn over the plot area at the current mouse location.
924      *
925      * @return A boolean.
926      */

927     public boolean getHorizontalAxisTrace() {
928         return this.horizontalAxisTrace;
929     }
930     
931     /**
932      * A flag that controls trace lines on the horizontal axis.
933      *
934      * @param flag <code>true</code> enables trace lines for the mouse
935      * pointer on the horizontal axis.
936      */

937     public void setHorizontalAxisTrace(boolean flag) {
938         this.horizontalAxisTrace = flag;
939     }
940     
941     /**
942      * Returns the horizontal trace line.
943      *
944      * @return The horizontal trace line (possibly <code>null</code>).
945      */

946     protected Line2D JavaDoc getHorizontalTraceLine() {
947         return this.horizontalTraceLine;
948     }
949     
950     /**
951      * Sets the horizontal trace line.
952      *
953      * @param line the line (<code>null</code> permitted).
954      */

955     protected void setHorizontalTraceLine(Line2D JavaDoc line) {
956         this.horizontalTraceLine = line;
957     }
958
959     /**
960      * Returns the flag that controls whether or not a vertical axis trace
961      * line is drawn over the plot area at the current mouse location.
962      *
963      * @return A boolean.
964      */

965     public boolean getVerticalAxisTrace() {
966         return this.verticalAxisTrace;
967     }
968     
969     /**
970      * A flag that controls trace lines on the vertical axis.
971      *
972      * @param flag <code>true</code> enables trace lines for the mouse
973      * pointer on the vertical axis.
974      */

975     public void setVerticalAxisTrace(boolean flag) {
976         this.verticalAxisTrace = flag;
977     }
978
979     /**
980      * Returns the vertical trace line.
981      *
982      * @return The vertical trace line (possibly <code>null</code>).
983      */

984     protected Line2D JavaDoc getVerticalTraceLine() {
985         return this.verticalTraceLine;
986     }
987     
988     /**
989      * Sets the vertical trace line.
990      *
991      * @param line the line (<code>null</code> permitted).
992      */

993     protected void setVerticalTraceLine(Line2D JavaDoc line) {
994         this.verticalTraceLine = line;
995     }
996
997     /**
998      * Returns <code>true</code> if file extensions should be enforced, and
999      * <code>false</code> otherwise.
1000     *
1001     * @return The flag.
1002     */

1003    public boolean isEnforceFileExtensions() {
1004        return this.enforceFileExtensions;
1005    }
1006
1007    /**
1008     * Sets a flag that controls whether or not file extensions are enforced.
1009     *
1010     * @param enforce the new flag value.
1011     */

1012    public void setEnforceFileExtensions(boolean enforce) {
1013        this.enforceFileExtensions = enforce;
1014    }
1015
1016    /**
1017     * Switches the display of tooltips for the panel on or off. Note that
1018     * tooltips can only be displayed if the chart has been configured to
1019     * generate tooltip items.
1020     *
1021     * @param flag <code>true</code> to enable tooltips, <code>false</code> to
1022     * disable tooltips.
1023     */

1024    public void setDisplayToolTips(boolean flag) {
1025        if (flag) {
1026            ToolTipManager.sharedInstance().registerComponent(this);
1027        }
1028        else {
1029            ToolTipManager.sharedInstance().unregisterComponent(this);
1030        }
1031    }
1032
1033    /**
1034     * Returns a string for the tooltip.
1035     *
1036     * @param e the mouse event.
1037     *
1038     * @return A tool tip or <code>null</code> if no tooltip is available.
1039     */

1040    public String JavaDoc getToolTipText(MouseEvent JavaDoc e) {
1041
1042        String JavaDoc result = null;
1043        if (this.info != null) {
1044            EntityCollection entities = this.info.getEntityCollection();
1045            if (entities != null) {
1046                Insets JavaDoc insets = getInsets();
1047                ChartEntity entity = entities.getEntity(
1048                    (int) ((e.getX() - insets.left) / this.scaleX),
1049                    (int) ((e.getY() - insets.top) / this.scaleY)
1050                );
1051                if (entity != null) {
1052                    result = entity.getToolTipText();
1053                }
1054            }
1055        }
1056        return result;
1057
1058    }
1059
1060    /**
1061     * Translates a Java2D point on the chart to a screen location.
1062     *
1063     * @param java2DPoint the Java2D point.
1064     *
1065     * @return The screen location.
1066     */

1067    public Point JavaDoc translateJava2DToScreen(Point2D JavaDoc java2DPoint) {
1068        Insets JavaDoc insets = getInsets();
1069        int x = (int) (java2DPoint.getX() * this.scaleX + insets.left);
1070        int y = (int) (java2DPoint.getY() * this.scaleY + insets.top);
1071        return new Point JavaDoc(x, y);
1072    }
1073
1074    /**
1075     * Translates a screen location to a Java2D point.
1076     *
1077     * @param screenPoint the screen location.
1078     *
1079     * @return The Java2D coordinates.
1080     */

1081    public Point2D JavaDoc translateScreenToJava2D(Point JavaDoc screenPoint) {
1082        Insets JavaDoc insets = getInsets();
1083        double x = (screenPoint.getX() - insets.left) / this.scaleX;
1084        double y = (screenPoint.getY() - insets.top) / this.scaleY;
1085        return new Point2D.Double JavaDoc(x, y);
1086    }
1087
1088    /**
1089     * Applies any scaling that is in effect for the chart drawing to the
1090     * given rectangle.
1091     *
1092     * @param rect the rectangle.
1093     *
1094     * @return A new scaled rectangle.
1095     */

1096    public Rectangle2D JavaDoc scale(Rectangle2D JavaDoc rect) {
1097        Insets JavaDoc insets = getInsets();
1098        double x = rect.getX() * getScaleX() + insets.left;
1099        double y = rect.getY() * this.getScaleY() + insets.top;
1100        double w = rect.getWidth() * this.getScaleX();
1101        double h = rect.getHeight() * this.getScaleY();
1102        return new Rectangle2D.Double JavaDoc(x, y, w, h);
1103    }
1104
1105    /**
1106     * Returns the chart entity at a given point.
1107     * <P>
1108     * This method will return null if there is (a) no entity at the given
1109     * point, or (b) no entity collection has been generated.
1110     *
1111     * @param viewX the x-coordinate.
1112     * @param viewY the y-coordinate.
1113     *
1114     * @return The chart entity (possibly <code>null</code>).
1115     */

1116    public ChartEntity getEntityForPoint(int viewX, int viewY) {
1117
1118        ChartEntity result = null;
1119        if (this.info != null) {
1120            Insets JavaDoc insets = getInsets();
1121            double x = (viewX - insets.left) / this.scaleX;
1122            double y = (viewY - insets.top) / this.scaleY;
1123            EntityCollection entities = this.info.getEntityCollection();
1124            result = entities != null ? entities.getEntity(x, y) : null;
1125        }
1126        return result;
1127
1128    }
1129
1130    /**
1131     * Returns the flag that controls whether or not the offscreen buffer
1132     * needs to be refreshed.
1133     *
1134     * @return A boolean.
1135     */

1136    public boolean getRefreshBuffer() {
1137        return this.refreshBuffer;
1138    }
1139    
1140    /**
1141     * Sets the refresh buffer flag. This flag is used to avoid unnecessary
1142     * redrawing of the chart when the offscreen image buffer is used.
1143     *
1144     * @param flag <code>true</code> indicate, that the buffer should be
1145     * refreshed.
1146     */

1147    public void setRefreshBuffer(boolean flag) {
1148        this.refreshBuffer = flag;
1149    }
1150
1151    /**
1152     * Paints the component by drawing the chart to fill the entire component,
1153     * but allowing for the insets (which will be non-zero if a border has been
1154     * set for this component). To increase performance (at the expense of
1155     * memory), an off-screen buffer image can be used.
1156     *
1157     * @param g the graphics device for drawing on.
1158     */

1159    public void paintComponent(Graphics JavaDoc g) {
1160
1161        super.paintComponent(g);
1162        if (this.chart == null) {
1163            return;
1164        }
1165        Graphics2D JavaDoc g2 = (Graphics2D JavaDoc) g.create();
1166
1167        // first determine the size of the chart rendering area...
1168
Dimension JavaDoc size = getSize();
1169        Insets JavaDoc insets = getInsets();
1170        Rectangle2D JavaDoc available = new Rectangle2D.Double JavaDoc(
1171            insets.left, insets.top,
1172            size.getWidth() - insets.left - insets.right,
1173            size.getHeight() - insets.top - insets.bottom
1174        );
1175
1176        // work out if scaling is required...
1177
boolean scale = false;
1178        double drawWidth = available.getWidth();
1179        double drawHeight = available.getHeight();
1180        this.scaleX = 1.0;
1181        this.scaleY = 1.0;
1182
1183        if (drawWidth < this.minimumDrawWidth) {
1184            this.scaleX = drawWidth / this.minimumDrawWidth;
1185            drawWidth = this.minimumDrawWidth;
1186            scale = true;
1187        }
1188        else if (drawWidth > this.maximumDrawWidth) {
1189            this.scaleX = drawWidth / this.maximumDrawWidth;
1190            drawWidth = this.maximumDrawWidth;
1191            scale = true;
1192        }
1193
1194        if (drawHeight < this.minimumDrawHeight) {
1195            this.scaleY = drawHeight / this.minimumDrawHeight;
1196            drawHeight = this.minimumDrawHeight;
1197            scale = true;
1198        }
1199        else if (drawHeight > this.maximumDrawHeight) {
1200            this.scaleY = drawHeight / this.maximumDrawHeight;
1201            drawHeight = this.maximumDrawHeight;
1202            scale = true;
1203        }
1204
1205        Rectangle2D JavaDoc chartArea = new Rectangle2D.Double JavaDoc(
1206            0.0, 0.0, drawWidth, drawHeight
1207        );
1208
1209        // are we using the chart buffer?
1210
if (this.useBuffer) {
1211
1212            // do we need to resize the buffer?
1213
if ((this.chartBuffer == null)
1214                    || (this.chartBufferWidth != available.getWidth())
1215                    || (this.chartBufferHeight != available.getHeight())
1216            ) {
1217                this.chartBufferWidth = (int) available.getWidth();
1218                this.chartBufferHeight = (int) available.getHeight();
1219                this.chartBuffer = createImage(
1220                    this.chartBufferWidth, this.chartBufferHeight
1221                );
1222                this.refreshBuffer = true;
1223            }
1224
1225            // do we need to redraw the buffer?
1226
if (this.refreshBuffer) {
1227
1228                Rectangle2D JavaDoc bufferArea = new Rectangle2D.Double JavaDoc(
1229                    0, 0, this.chartBufferWidth, this.chartBufferHeight
1230                );
1231
1232                Graphics2D JavaDoc bufferG2
1233                    = (Graphics2D JavaDoc) this.chartBuffer.getGraphics();
1234                if (scale) {
1235                    AffineTransform JavaDoc saved = bufferG2.getTransform();
1236                    AffineTransform JavaDoc st = AffineTransform.getScaleInstance(
1237                        this.scaleX, this.scaleY
1238                    );
1239                    bufferG2.transform(st);
1240                    this.chart.draw(
1241                        bufferG2, chartArea, this.anchor, this.info
1242                    );
1243                    bufferG2.setTransform(saved);
1244                }
1245                else {
1246                    this.chart.draw(
1247                        bufferG2, bufferArea, this.anchor, this.info
1248                    );
1249                }
1250
1251                this.refreshBuffer = false;
1252
1253            }
1254
1255            // zap the buffer onto the panel...
1256
g2.drawImage(this.chartBuffer, insets.left, insets.right, this);
1257
1258        }
1259
1260        // or redrawing the chart every time...
1261
else {
1262
1263            AffineTransform JavaDoc saved = g2.getTransform();
1264            g2.translate(insets.left, insets.top);
1265            if (scale) {
1266                AffineTransform JavaDoc st = AffineTransform.getScaleInstance(
1267                    this.scaleX, this.scaleY
1268                );
1269                g2.transform(st);
1270            }
1271            this.chart.draw(g2, chartArea, this.anchor, this.info);
1272            g2.setTransform(saved);
1273
1274        }
1275
1276        this.anchor = null;
1277        this.verticalTraceLine = null;
1278        this.horizontalTraceLine = null;
1279
1280    }
1281
1282    /**
1283     * Receives notification of changes to the chart, and redraws the chart.
1284     *
1285     * @param event details of the chart change event.
1286     */

1287    public void chartChanged(ChartChangeEvent event) {
1288        this.refreshBuffer = true;
1289        repaint();
1290    }
1291
1292    /**
1293     * Receives notification of a chart progress event.
1294     *
1295     * @param event the event.
1296     */

1297    public void chartProgress(ChartProgressEvent event) {
1298        // does nothing - override if necessary
1299
}
1300
1301    /**
1302     * Handles action events generated by the popup menu.
1303     *
1304     * @param event the event.
1305     */

1306    public void actionPerformed(ActionEvent JavaDoc event) {
1307
1308        String JavaDoc command = event.getActionCommand();
1309
1310        if (command.equals(PROPERTIES_COMMAND)) {
1311            attemptEditChartProperties();
1312        }
1313        else if (command.equals(SAVE_COMMAND)) {
1314            try {
1315                doSaveAs();
1316            }
1317            catch (IOException JavaDoc e) {
1318                e.printStackTrace();
1319            }
1320        }
1321        else if (command.equals(PRINT_COMMAND)) {
1322            createChartPrintJob();
1323        }
1324        else if (command.equals(ZOOM_IN_BOTH_COMMAND)) {
1325            zoomInBoth(this.zoomPoint.getX(), this.zoomPoint.getY());
1326        }
1327        else if (command.equals(ZOOM_IN_DOMAIN_COMMAND)) {
1328            zoomInDomain(this.zoomPoint.getX(), this.zoomPoint.getY());
1329        }
1330        else if (command.equals(ZOOM_IN_RANGE_COMMAND)) {
1331            zoomInRange(this.zoomPoint.getX(), this.zoomPoint.getY());
1332        }
1333        else if (command.equals(ZOOM_OUT_BOTH_COMMAND)) {
1334            zoomOutBoth(this.zoomPoint.getX(), this.zoomPoint.getY());
1335        }
1336        else if (command.equals(ZOOM_OUT_DOMAIN_COMMAND)) {
1337            zoomOutDomain(this.zoomPoint.getX(), this.zoomPoint.getY());
1338        }
1339        else if (command.equals(ZOOM_OUT_RANGE_COMMAND)) {
1340            zoomOutRange(this.zoomPoint.getX(), this.zoomPoint.getY());
1341        }
1342        else if (command.equals(ZOOM_RESET_BOTH_COMMAND)) {
1343            restoreAutoBounds();
1344        }
1345        else if (command.equals(ZOOM_RESET_DOMAIN_COMMAND)) {
1346            restoreAutoDomainBounds();
1347        }
1348        else if (command.equals(ZOOM_RESET_RANGE_COMMAND)) {
1349            restoreAutoRangeBounds();
1350        }
1351
1352    }
1353
1354    /**
1355     * Handles a 'mouse entered' event. This method changes the tooltip delays
1356     * of ToolTipManager.sharedInstance() to the possibly different values set
1357     * for this chart panel.
1358     *
1359     * @param e the mouse event.
1360     */

1361    public void mouseEntered(MouseEvent JavaDoc e) {
1362        if (!this.ownToolTipDelaysActive) {
1363            ToolTipManager JavaDoc ttm = ToolTipManager.sharedInstance();
1364            
1365            this.originalToolTipInitialDelay = ttm.getInitialDelay();
1366            ttm.setInitialDelay(this.ownToolTipInitialDelay);
1367    
1368            this.originalToolTipReshowDelay = ttm.getReshowDelay();
1369            ttm.setReshowDelay(this.ownToolTipReshowDelay);
1370            
1371            this.originalToolTipDismissDelay = ttm.getDismissDelay();
1372            ttm.setDismissDelay(this.ownToolTipDismissDelay);
1373    
1374            this.ownToolTipDelaysActive = true;
1375        }
1376    }
1377
1378    /**
1379     * Handles a 'mouse exited' event. This method resets the tooltip delays of
1380     * ToolTipManager.sharedInstance() to their
1381     * original values in effect before mouseEntered()
1382     *
1383     * @param e the mouse event.
1384     */

1385    public void mouseExited(MouseEvent JavaDoc e) {
1386        if (this.ownToolTipDelaysActive) {
1387            // restore original tooltip dealys
1388
ToolTipManager JavaDoc ttm = ToolTipManager.sharedInstance();
1389            ttm.setInitialDelay(this.originalToolTipInitialDelay);
1390            ttm.setReshowDelay(this.originalToolTipReshowDelay);
1391            ttm.setDismissDelay(this.originalToolTipDismissDelay);
1392            this.ownToolTipDelaysActive = false;
1393        }
1394    }
1395
1396    /**
1397     * Handles a 'mouse pressed' event.
1398     * <P>
1399     * This event is the popup trigger on Unix/Linux. For Windows, the popup
1400     * trigger is the 'mouse released' event.
1401     *
1402     * @param e The mouse event.
1403     */

1404    public void mousePressed(MouseEvent JavaDoc e) {
1405        if (this.zoomRectangle == null) {
1406            Rectangle2D JavaDoc screenDataArea = getScreenDataArea(e.getX(), e.getY());
1407            if (screenDataArea != null) {
1408                this.zoomPoint = getPointInRectangle(
1409                    e.getX(), e.getY(), screenDataArea
1410                );
1411            }
1412            else {
1413                this.zoomPoint = null;
1414            }
1415            if (e.isPopupTrigger()) {
1416                if (this.popup != null) {
1417                    displayPopupMenu(e.getX(), e.getY());
1418                }
1419            }
1420        }
1421    }
1422    
1423    /**
1424     * Returns a point based on (x, y) but constrained to be within the bounds
1425     * of the given rectangle. This method could be moved to JCommon.
1426     *
1427     * @param x the x-coordinate.
1428     * @param y the y-coordinate.
1429     * @param area the rectangle (<code>null</code> not permitted).
1430     *
1431     * @return A point within the rectangle.
1432     */

1433    private Point JavaDoc getPointInRectangle(int x, int y, Rectangle2D JavaDoc area) {
1434        x = (int) Math.max(
1435            Math.ceil(area.getMinX()), Math.min(x, Math.floor(area.getMaxX()))
1436        );
1437        y = (int) Math.max(
1438            Math.ceil(area.getMinY()), Math.min(y, Math.floor(area.getMaxY()))
1439        );
1440        return new Point JavaDoc(x, y);
1441    }
1442
1443    /**
1444     * Handles a 'mouse dragged' event.
1445     *
1446     * @param e the mouse event.
1447     */

1448    public void mouseDragged(MouseEvent JavaDoc e) {
1449
1450        // if the popup menu has already been triggered, then ignore dragging...
1451
if (this.popup != null && this.popup.isShowing()) {
1452            return;
1453        }
1454        // if no initial zoom point was set, ignore dragging...
1455
if (this.zoomPoint == null) {
1456            return;
1457        }
1458        Graphics2D JavaDoc g2 = (Graphics2D JavaDoc) getGraphics();
1459
1460        // use XOR to erase the previous zoom rectangle (if any)...
1461
g2.setXORMode(java.awt.Color.gray);
1462        if (this.zoomRectangle != null) {
1463            if (this.fillZoomRectangle) {
1464                g2.fill(this.zoomRectangle);
1465            }
1466            else {
1467                g2.draw(this.zoomRectangle);
1468            }
1469        }
1470
1471        boolean hZoom = false;
1472        boolean vZoom = false;
1473        if (this.orientation == PlotOrientation.HORIZONTAL) {
1474            hZoom = this.rangeZoomable;
1475            vZoom = this.domainZoomable;
1476        }
1477        else {
1478            hZoom = this.domainZoomable;
1479            vZoom = this.rangeZoomable;
1480        }
1481        Rectangle2D JavaDoc scaledDataArea = getScreenDataArea(
1482            (int) this.zoomPoint.getX(), (int) this.zoomPoint.getY()
1483        );
1484        if (hZoom && vZoom) {
1485            // selected rectangle shouldn't extend outside the data area...
1486
double xmax = Math.min(e.getX(), scaledDataArea.getMaxX());
1487            double ymax = Math.min(e.getY(), scaledDataArea.getMaxY());
1488            this.zoomRectangle = new Rectangle2D.Double JavaDoc(
1489                this.zoomPoint.getX(), this.zoomPoint.getY(),
1490                xmax - this.zoomPoint.getX(), ymax - this.zoomPoint.getY()
1491            );
1492        }
1493        else if (hZoom) {
1494            double xmax = Math.min(e.getX(), scaledDataArea.getMaxX());
1495            this.zoomRectangle = new Rectangle2D.Double JavaDoc(
1496                this.zoomPoint.getX(), scaledDataArea.getMinY(),
1497                xmax - this.zoomPoint.getX(), scaledDataArea.getHeight()
1498            );
1499        }
1500        else if (vZoom) {
1501            double ymax = Math.min(e.getY(), scaledDataArea.getMaxY());
1502            this.zoomRectangle = new Rectangle2D.Double JavaDoc(
1503                scaledDataArea.getMinX(), this.zoomPoint.getY(),
1504                scaledDataArea.getWidth(), ymax - this.zoomPoint.getY()
1505            );
1506        }
1507
1508        if (this.zoomRectangle != null) {
1509            // use XOR to draw the new zoom rectangle...
1510
if (this.fillZoomRectangle) {
1511                g2.fill(this.zoomRectangle);
1512            }
1513            else {
1514                g2.draw(this.zoomRectangle);
1515            }
1516        }
1517        g2.dispose();
1518
1519    }
1520
1521    /**
1522     * Handles a 'mouse released' event. On Windows, we need to check if this
1523     * is a popup trigger, but only if we haven't already been tracking a zoom
1524     * rectangle.
1525     *
1526     * @param e information about the event.
1527     */

1528    public void mouseReleased(MouseEvent JavaDoc e) {
1529
1530        if (this.zoomRectangle != null) {
1531            boolean hZoom = false;
1532            boolean vZoom = false;
1533            if (this.orientation == PlotOrientation.HORIZONTAL) {
1534                hZoom = this.rangeZoomable;
1535                vZoom = this.domainZoomable;
1536            }
1537            else {
1538                hZoom = this.domainZoomable;
1539                vZoom = this.rangeZoomable;
1540            }
1541            
1542            boolean zoomTrigger1 = hZoom && Math.abs(e.getX()
1543                - this.zoomPoint.getX()) >= this.zoomTriggerDistance;
1544            boolean zoomTrigger2 = vZoom && Math.abs(e.getY()
1545                - this.zoomPoint.getY()) >= this.zoomTriggerDistance;
1546            if (zoomTrigger1 || zoomTrigger2) {
1547                if ((hZoom && (e.getX() < this.zoomPoint.getX()))
1548                    || (vZoom && (e.getY() < this.zoomPoint.getY()))) {
1549                    restoreAutoBounds();
1550                }
1551                else {
1552                    double x, y, w, h;
1553                    Rectangle2D JavaDoc screenDataArea = getScreenDataArea(
1554                        (int) this.zoomPoint.getX(),
1555                        (int) this.zoomPoint.getY()
1556                    );
1557                    // for mouseReleased event, (horizontalZoom || verticalZoom)
1558
// will be true, so we can just test for either being false;
1559
// otherwise both are true
1560
if (!vZoom) {
1561                        x = this.zoomPoint.getX();
1562                        y = screenDataArea.getMinY();
1563                        w = Math.min(
1564                            this.zoomRectangle.getWidth(),
1565                            screenDataArea.getMaxX() - this.zoomPoint.getX()
1566                        );
1567                        h = screenDataArea.getHeight();
1568                    }
1569                    else if (!hZoom) {
1570                        x = screenDataArea.getMinX();
1571                        y = this.zoomPoint.getY();
1572                        w = screenDataArea.getWidth();
1573                        h = Math.min(
1574                            this.zoomRectangle.getHeight(),
1575                            screenDataArea.getMaxY() - this.zoomPoint.getY()
1576                        );
1577                    }
1578                    else {
1579                        x = this.zoomPoint.getX();
1580                        y = this.zoomPoint.getY();
1581                        w = Math.min(
1582                            this.zoomRectangle.getWidth(),
1583                            screenDataArea.getMaxX() - this.zoomPoint.getX()
1584                        );
1585                        h = Math.min(
1586                            this.zoomRectangle.getHeight(),
1587                            screenDataArea.getMaxY() - this.zoomPoint.getY()
1588                        );
1589                    }
1590                    Rectangle2D JavaDoc zoomArea = new Rectangle2D.Double JavaDoc(x, y, w, h);
1591                    zoom(zoomArea);
1592                }
1593                this.zoomPoint = null;
1594                this.zoomRectangle = null;
1595            }
1596            else {
1597                Graphics2D JavaDoc g2 = (Graphics2D JavaDoc) getGraphics();
1598                g2.setXORMode(java.awt.Color.gray);
1599                if (this.fillZoomRectangle) {
1600                    g2.fill(this.zoomRectangle);
1601                }
1602                else {
1603                    g2.draw(this.zoomRectangle);
1604                }
1605                g2.dispose();
1606                this.zoomPoint = null;
1607                this.zoomRectangle = null;
1608            }
1609
1610        }
1611
1612        else if (e.isPopupTrigger()) {
1613            if (this.popup != null) {
1614                displayPopupMenu(e.getX(), e.getY());
1615            }
1616        }
1617
1618    }
1619
1620    /**
1621     * Receives notification of mouse clicks on the panel. These are
1622     * translated and passed on to any registered chart mouse click listeners.
1623     *
1624     * @param event Information about the mouse event.
1625     */

1626    public void mouseClicked(MouseEvent JavaDoc event) {
1627
1628        Insets JavaDoc insets = getInsets();
1629        int x = (int) ((event.getX() - insets.left) / this.scaleX);
1630        int y = (int) ((event.getY() - insets.top) / this.scaleY);
1631
1632        // old 'handle click' code...
1633
//chart.handleClick(x, y, this.info);
1634
this.anchor = new Point2D.Double JavaDoc(x, y);
1635        this.chart.setNotify(true); // force a redraw
1636
// new entity code...
1637
if (this.chartMouseListeners.isEmpty()) {
1638            return;
1639        }
1640
1641        ChartEntity entity = null;
1642        if (this.info != null) {
1643            EntityCollection entities = this.info.getEntityCollection();
1644            if (entities != null) {
1645                entity = entities.getEntity(x, y);
1646            }
1647        }
1648        ChartMouseEvent chartEvent = new ChartMouseEvent(
1649            getChart(), event, entity
1650        );
1651
1652        Iterator JavaDoc iterator = this.chartMouseListeners.iterator();
1653        while (iterator.hasNext()) {
1654            ChartMouseListener listener = (ChartMouseListener) iterator.next();
1655            listener.chartMouseClicked(chartEvent);
1656        }
1657
1658    }
1659
1660    /**
1661     * Implementation of the MouseMotionListener's method.
1662     *
1663     * @param e the event.
1664     */

1665    public void mouseMoved(MouseEvent JavaDoc e) {
1666        if (this.horizontalAxisTrace) {
1667            drawHorizontalAxisTrace(e.getX());
1668        }
1669        if (this.verticalAxisTrace) {
1670            drawVerticalAxisTrace(e.getY());
1671        }
1672        if (this.chartMouseListeners.isEmpty()) {
1673            return;
1674        }
1675        Insets JavaDoc insets = getInsets();
1676        int x = (int) ((e.getX() - insets.left) / this.scaleX);
1677        int y = (int) ((e.getY() - insets.top) / this.scaleY);
1678
1679        ChartEntity entity = null;
1680        if (this.info != null) {
1681            EntityCollection entities = this.info.getEntityCollection();
1682            if (entities != null) {
1683                entity = entities.getEntity(x, y);
1684            }
1685        }
1686        ChartMouseEvent event = new ChartMouseEvent(getChart(), e, entity);
1687
1688        Iterator JavaDoc iterator = this.chartMouseListeners.iterator();
1689        while (iterator.hasNext()) {
1690            ChartMouseListener listener = (ChartMouseListener) iterator.next();
1691            listener.chartMouseMoved(event);
1692        }
1693
1694    }
1695
1696    /**
1697     * Zooms in on an anchor point (specified in screen coordinate space).
1698     *
1699     * @param x the x value (in screen coordinates).
1700     * @param y the y value (in screen coordinates).
1701     */

1702    public void zoomInBoth(double x, double y) {
1703        zoomInDomain(x, y);
1704        zoomInRange(x, y);
1705    }
1706
1707    /**
1708     * Decreases the length of the domain axis, centered about the given
1709     * coordinate on the screen. The length of the domain axis is reduced
1710     * by the value of {@link #getZoomInFactor()}.
1711     *
1712     * @param x the x coordinate (in screen coordinates).
1713     * @param y the y-coordinate (in screen coordinates).
1714     */

1715    public void zoomInDomain(double x, double y) {
1716        Plot p = this.chart.getPlot();
1717        if (p instanceof Zoomable) {
1718            Zoomable plot = (Zoomable) p;
1719            plot.zoomDomainAxes(
1720                this.zoomInFactor, this.info.getPlotInfo(),
1721                translateScreenToJava2D(new Point JavaDoc((int) x, (int) y))
1722            );
1723        }
1724    }
1725
1726    /**
1727     * Decreases the length of the range axis, centered about the given
1728     * coordinate on the screen. The length of the range axis is reduced by
1729     * the value of {@link #getZoomInFactor()}.
1730     *
1731     * @param x the x-coordinate (in screen coordinates).
1732     * @param y the y coordinate (in screen coordinates).
1733     */

1734    public void zoomInRange(double x, double y) {
1735        Plot p = this.chart.getPlot();
1736        if (p instanceof Zoomable) {
1737            Zoomable z = (Zoomable) p;
1738            z.zoomRangeAxes(
1739                this.zoomInFactor, this.info.getPlotInfo(),
1740                translateScreenToJava2D(new Point JavaDoc((int) x, (int) y))
1741            );
1742        }
1743    }
1744
1745    /**
1746     * Zooms out on an anchor point (specified in screen coordinate space).
1747     *
1748     * @param x the x value (in screen coordinates).
1749     * @param y the y value (in screen coordinates).
1750     */

1751    public void zoomOutBoth(double x, double y) {
1752        zoomOutDomain(x, y);
1753        zoomOutRange(x, y);
1754    }
1755
1756    /**
1757     * Increases the length of the domain axis, centered about the given
1758     * coordinate on the screen. The length of the domain axis is increased
1759     * by the value of {@link #getZoomOutFactor()}.
1760     *
1761     * @param x the x coordinate (in screen coordinates).
1762     * @param y the y-coordinate (in screen coordinates).
1763     */

1764    public void zoomOutDomain(double x, double y) {
1765        Plot p = this.chart.getPlot();
1766        if (p instanceof Zoomable) {
1767            Zoomable z = (Zoomable) p;
1768            z.zoomDomainAxes(
1769                this.zoomOutFactor, this.info.getPlotInfo(),
1770                translateScreenToJava2D(new Point JavaDoc((int) x, (int) y))
1771            );
1772        }
1773    }
1774
1775    /**
1776     * Increases the length the range axis, centered about the given
1777     * coordinate on the screen. The length of the range axis is increased
1778     * by the value of {@link #getZoomOutFactor()}.
1779     *
1780     * @param x the x coordinate (in screen coordinates).
1781     * @param y the y-coordinate (in screen coordinates).
1782     */

1783    public void zoomOutRange(double x, double y) {
1784        Plot p = this.chart.getPlot();
1785        if (p instanceof Zoomable) {
1786            Zoomable z = (Zoomable) p;
1787            z.zoomRangeAxes(
1788                this.zoomOutFactor, this.info.getPlotInfo(),
1789                translateScreenToJava2D(new Point JavaDoc((int) x, (int) y))
1790            );
1791        }
1792    }
1793
1794    /**
1795     * Zooms in on a selected region.
1796     *
1797     * @param selection the selected region.
1798     */

1799    public void zoom(Rectangle2D JavaDoc selection) {
1800
1801        // get the origin of the zoom selection in the Java2D space used for
1802
// drawing the chart (that is, before any scaling to fit the panel)
1803
Point2D JavaDoc selectOrigin = translateScreenToJava2D(
1804            new Point JavaDoc(
1805                (int) Math.ceil(selection.getX()),
1806                (int) Math.ceil(selection.getY())
1807            )
1808        );
1809        PlotRenderingInfo plotInfo = this.info.getPlotInfo();
1810        Rectangle2D JavaDoc scaledDataArea = getScreenDataArea(
1811            (int) selection.getCenterX(), (int) selection.getCenterY()
1812        );
1813        if ((selection.getHeight() > 0) && (selection.getWidth() > 0)) {
1814
1815            double hLower = (selection.getMinX() - scaledDataArea.getMinX())
1816                / scaledDataArea.getWidth();
1817            double hUpper = (selection.getMaxX() - scaledDataArea.getMinX())
1818                / scaledDataArea.getWidth();
1819            double vLower = (scaledDataArea.getMaxY() - selection.getMaxY())
1820                / scaledDataArea.getHeight();
1821            double vUpper = (scaledDataArea.getMaxY() - selection.getMinY())
1822                / scaledDataArea.getHeight();
1823
1824            Plot p = this.chart.getPlot();
1825            if (p instanceof Zoomable) {
1826                Zoomable z = (Zoomable) p;
1827                if (z.getOrientation() == PlotOrientation.HORIZONTAL) {
1828                    z.zoomDomainAxes(vLower, vUpper, plotInfo, selectOrigin);
1829                    z.zoomRangeAxes(hLower, hUpper, plotInfo, selectOrigin);
1830                }
1831                else {
1832                    z.zoomDomainAxes(hLower, hUpper, plotInfo, selectOrigin);
1833                    z.zoomRangeAxes(vLower, vUpper, plotInfo, selectOrigin);
1834                }
1835            }
1836
1837        }
1838
1839    }
1840
1841    /**
1842     * Restores the auto-range calculation on both axes.
1843     */

1844    public void restoreAutoBounds() {
1845        restoreAutoDomainBounds();
1846        restoreAutoRangeBounds();
1847    }
1848
1849    /**
1850     * Restores the auto-range calculation on the domain axis.
1851     */

1852    public void restoreAutoDomainBounds() {
1853        Plot p = this.chart.getPlot();
1854        if (p instanceof Zoomable) {
1855            Zoomable z = (Zoomable) p;
1856            z.zoomDomainAxes(0.0, this.info.getPlotInfo(), this.zoomPoint);
1857        }
1858    }
1859
1860    /**
1861     * Restores the auto-range calculation on the range axis.
1862     */

1863    public void restoreAutoRangeBounds() {
1864        Plot p = this.chart.getPlot();
1865        if (p instanceof ValueAxisPlot) {
1866            Zoomable z = (Zoomable) p;
1867            z.zoomRangeAxes(0.0, this.info.getPlotInfo(), this.zoomPoint);
1868        }
1869    }
1870
1871    /**
1872     * Returns the data area for the chart (the area inside the axes) with the
1873     * current scaling applied (that is, the area as it appears on screen).
1874     *
1875     * @return The scaled data area.
1876     */

1877    public Rectangle2D JavaDoc getScreenDataArea() {
1878        Rectangle2D JavaDoc dataArea = this.info.getPlotInfo().getDataArea();
1879        Insets JavaDoc insets = getInsets();
1880        double x = dataArea.getX() * this.scaleX + insets.left;
1881        double y = dataArea.getY() * this.scaleY + insets.top;
1882        double w = dataArea.getWidth() * this.scaleX;
1883        double h = dataArea.getHeight() * this.scaleY;
1884        return new Rectangle2D.Double JavaDoc(x, y, w, h);
1885    }
1886    
1887    /**
1888     * Returns the data area (the area inside the axes) for the plot or subplot,
1889     * with the current scaling applied.
1890     *
1891     * @param x the x-coordinate (for subplot selection).
1892     * @param y the y-coordinate (for subplot selection).
1893     *
1894     * @return The scaled data area.
1895     */

1896    public Rectangle2D JavaDoc getScreenDataArea(int x, int y) {
1897        PlotRenderingInfo plotInfo = this.info.getPlotInfo();
1898        Rectangle2D JavaDoc result;
1899        if (plotInfo.getSubplotCount() == 0) {
1900            result = getScreenDataArea();
1901        }
1902        else {
1903            // get the origin of the zoom selection in the Java2D space used for
1904
// drawing the chart (that is, before any scaling to fit the panel)
1905
Point2D JavaDoc selectOrigin = translateScreenToJava2D(new Point JavaDoc(x, y));
1906            int subplotIndex = plotInfo.getSubplotIndex(selectOrigin);
1907            if (subplotIndex == -1) {
1908                return null;
1909            }
1910            result = scale(plotInfo.getSubplotInfo(subplotIndex).getDataArea());
1911        }
1912        return result;
1913    }
1914    
1915    /**
1916     * Returns the initial tooltip delay value used inside this chart panel.
1917     *
1918     * @return An integer representing the initial delay value, in milliseconds.
1919     *
1920     * @see javax.swing.ToolTipManager#getInitialDelay()
1921     */

1922    public int getInitialDelay() {
1923        return this.ownToolTipInitialDelay;
1924    }
1925    
1926    /**
1927     * Returns the reshow tooltip delay value used inside this chart panel.
1928     *
1929     * @return An integer representing the reshow delay value, in milliseconds.
1930     *
1931     * @see javax.swing.ToolTipManager#getReshowDelay()
1932     */

1933    public int getReshowDelay() {
1934        return this.ownToolTipReshowDelay;
1935    }
1936
1937    /**
1938     * Returns the dismissal tooltip delay value used inside this chart panel.
1939     *
1940     * @return An integer representing the dismissal delay value, in
1941     * milliseconds.
1942     *
1943     * @see javax.swing.ToolTipManager#getDismissDelay()
1944     */

1945    public int getDismissDelay() {
1946        return this.ownToolTipDismissDelay;
1947    }
1948    
1949    /**
1950     * Specifies the initial delay value for this chart panel.
1951     *
1952     * @param delay the number of milliseconds to delay (after the cursor has
1953     * paused) before displaying.
1954     *
1955     * @see javax.swing.ToolTipManager#setInitialDelay(int)
1956     */

1957    public void setInitialDelay(int delay) {
1958        this.ownToolTipInitialDelay = delay;
1959    }
1960    
1961    /**
1962     * Specifies the amount of time before the user has to wait initialDelay
1963     * milliseconds before a tooltip will be shown.
1964     *
1965     * @param delay time in milliseconds
1966     *
1967     * @see javax.swing.ToolTipManager#setReshowDelay(int)
1968     */

1969    public void setReshowDelay(int delay) {
1970        this.ownToolTipReshowDelay = delay;
1971    }
1972
1973    /**
1974     * Specifies the dismissal delay value for this chart panel.
1975     *
1976     * @param delay the number of milliseconds to delay before taking away the
1977     * tooltip
1978     *
1979     * @see javax.swing.ToolTipManager#setDismissDelay(int)
1980     */

1981    public void setDismissDelay(int delay) {
1982        this.ownToolTipDismissDelay = delay;
1983    }
1984    
1985    /**
1986     * Returns the zoom in factor.
1987     *
1988     * @return The zoom in factor.
1989     */

1990    public double getZoomInFactor() {
1991        return this.zoomInFactor;
1992    }
1993    
1994    /**
1995     * Sets the zoom in factor.
1996     *
1997     * @param factor the factor.
1998     */

1999    public void setZoomInFactor(double factor) {
2000        this.zoomInFactor = factor;
2001    }
2002    
2003    /**
2004     * Returns the zoom out factor.
2005     *
2006     * @return The zoom out factor.
2007     */

2008    public double getZoomOutFactor() {
2009        return this.zoomOutFactor;
2010    }
2011    
2012    /**
2013     * Sets the zoom out factor.
2014     *
2015     * @param factor the factor.
2016     */

2017    public void setZoomOutFactor(double factor) {
2018        this.zoomOutFactor = factor;
2019    }
2020    
2021    /**
2022     * Draws a vertical line used to trace the mouse position to the horizontal
2023     * axis.
2024     *
2025     * @param x the x-coordinate of the trace line.
2026     */

2027    private void drawHorizontalAxisTrace(int x) {
2028
2029        Graphics2D JavaDoc g2 = (Graphics2D JavaDoc) getGraphics();
2030        Rectangle2D JavaDoc dataArea = getScreenDataArea();
2031
2032        g2.setXORMode(java.awt.Color.orange);
2033        if (((int) dataArea.getMinX() < x) && (x < (int) dataArea.getMaxX())) {
2034
2035            if (this.verticalTraceLine != null) {
2036                g2.draw(this.verticalTraceLine);
2037                this.verticalTraceLine.setLine(
2038                    x, (int) dataArea.getMinY(), x, (int) dataArea.getMaxY()
2039                );
2040            }
2041            else {
2042                this.verticalTraceLine = new Line2D.Float JavaDoc(
2043                    x, (int) dataArea.getMinY(), x, (int) dataArea.getMaxY()
2044                );
2045            }
2046            g2.draw(this.verticalTraceLine);
2047        }
2048
2049    }
2050
2051    /**
2052     * Draws a horizontal line used to trace the mouse position to the vertical
2053     * axis.
2054     *
2055     * @param y the y-coordinate of the trace line.
2056     */

2057    private void drawVerticalAxisTrace(int y) {
2058
2059        Graphics2D JavaDoc g2 = (Graphics2D JavaDoc) getGraphics();
2060        Rectangle2D JavaDoc dataArea = getScreenDataArea();
2061
2062        g2.setXORMode(java.awt.Color.orange);
2063        if (((int) dataArea.getMinY() < y) && (y < (int) dataArea.getMaxY())) {
2064
2065            if (this.horizontalTraceLine != null) {
2066                g2.draw(this.horizontalTraceLine);
2067                this.horizontalTraceLine.setLine(
2068                    (int) dataArea.getMinX(), y, (int) dataArea.getMaxX(), y
2069                );
2070            }
2071            else {
2072                this.horizontalTraceLine = new Line2D.Float JavaDoc(
2073                    (int) dataArea.getMinX(), y, (int) dataArea.getMaxX(), y
2074                );
2075            }
2076            g2.draw(this.horizontalTraceLine);
2077        }
2078
2079    }
2080
2081    /**
2082     * Displays a dialog that allows the user to edit the properties for the
2083     * current chart.
2084     */

2085    private void attemptEditChartProperties() {
2086
2087        ChartPropertyEditPanel panel = new ChartPropertyEditPanel(this.chart);
2088        int result =
2089            JOptionPane.showConfirmDialog(
2090                this, panel,
2091                localizationResources.getString("Chart_Properties"),
2092                JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE
2093            );
2094        if (result == JOptionPane.OK_OPTION) {
2095            panel.updateChartProperties(this.chart);
2096        }
2097
2098    }
2099
2100    /**
2101     * Opens a file chooser and gives the user an opportunity to save the chart
2102     * in PNG format.
2103     *
2104     * @throws IOException if there is an I/O error.
2105     */

2106    public void doSaveAs() throws IOException JavaDoc {
2107
2108        JFileChooser JavaDoc fileChooser = new JFileChooser JavaDoc();
2109        ExtensionFileFilter filter = new ExtensionFileFilter(
2110            localizationResources.getString("PNG_Image_Files"), ".png"
2111        );
2112        fileChooser.addChoosableFileFilter(filter);
2113
2114        int option = fileChooser.showSaveDialog(this);
2115        if (option == JFileChooser.APPROVE_OPTION) {
2116            String JavaDoc filename = fileChooser.getSelectedFile().getPath();
2117            if (isEnforceFileExtensions()) {
2118                if (!filename.endsWith(".png")) {
2119                    filename = filename + ".png";
2120                }
2121            }
2122            ChartUtilities.saveChartAsPNG(
2123                new File JavaDoc(filename), this.chart, getWidth(), getHeight()
2124            );
2125        }
2126
2127    }
2128
2129    /**
2130     * Creates a print job for the chart.
2131     */

2132    public void createChartPrintJob() {
2133
2134        PrinterJob JavaDoc job = PrinterJob.getPrinterJob();
2135        PageFormat JavaDoc pf = job.defaultPage();
2136        PageFormat JavaDoc pf2 = job.pageDialog(pf);
2137        if (pf2 != pf) {
2138            job.setPrintable(this, pf2);
2139            if (job.printDialog()) {
2140                try {
2141                    job.print();
2142                }
2143                catch (PrinterException JavaDoc e) {
2144                    JOptionPane.showMessageDialog(this, e);
2145                }
2146            }
2147        }
2148
2149    }
2150
2151    /**
2152     * Prints the chart on a single page.
2153     *
2154     * @param g the graphics context.
2155     * @param pf the page format to use.
2156     * @param pageIndex the index of the page. If not <code>0</code>, nothing
2157     * gets print.
2158     *
2159     * @return The result of printing.
2160     */

2161    public int print(Graphics JavaDoc g, PageFormat JavaDoc pf, int pageIndex) {
2162
2163        if (pageIndex != 0) {
2164            return NO_SUCH_PAGE;
2165        }
2166        Graphics2D JavaDoc g2 = (Graphics2D JavaDoc) g;
2167        double x = pf.getImageableX();
2168        double y = pf.getImageableY();
2169        double w = pf.getImageableWidth();
2170        double h = pf.getImageableHeight();
2171        this.chart.draw(
2172            g2, new Rectangle2D.Double JavaDoc(x, y, w, h), this.anchor, null
2173        );
2174        return PAGE_EXISTS;
2175
2176    }
2177
2178    /**
2179     * Adds a listener to the list of objects listening for chart mouse events.
2180     *
2181     * @param listener the listener (<code>null</code> not permitted).
2182     */

2183    public void addChartMouseListener(ChartMouseListener listener) {
2184        if (listener == null) {
2185            throw new IllegalArgumentException JavaDoc("Null 'listener' argument.");
2186        }
2187        this.chartMouseListeners.add(listener);
2188    }
2189
2190    /**
2191     * Removes a listener from the list of objects listening for chart mouse
2192     * events.
2193     *
2194     * @param listener the listener.
2195     */

2196    public void removeChartMouseListener(ChartMouseListener listener) {
2197        this.chartMouseListeners.remove(listener);
2198    }
2199
2200    /**
2201     * Creates a popup menu for the panel.
2202     *
2203     * @param properties include a menu item for the chart property editor.
2204     * @param save include a menu item for saving the chart.
2205     * @param print include a menu item for printing the chart.
2206     * @param zoom include menu items for zooming.
2207     *
2208     * @return The popup menu.
2209     */

2210    protected JPopupMenu JavaDoc createPopupMenu(boolean properties,
2211                                         boolean save,
2212                                         boolean print,
2213                                         boolean zoom) {
2214
2215        JPopupMenu JavaDoc result = new JPopupMenu JavaDoc("Chart:");
2216        boolean separator = false;
2217
2218        if (properties) {
2219            JMenuItem JavaDoc propertiesItem = new JMenuItem JavaDoc(
2220                localizationResources.getString("Properties...")
2221            );
2222            propertiesItem.setActionCommand(PROPERTIES_COMMAND);
2223            propertiesItem.addActionListener(this);
2224            result.add(propertiesItem);
2225            separator = true;
2226        }
2227
2228        if (save) {
2229            if (separator) {
2230                result.addSeparator();
2231                separator = false;
2232            }
2233            JMenuItem JavaDoc saveItem = new JMenuItem JavaDoc(
2234                localizationResources.getString("Save_as...")
2235            );
2236            saveItem.setActionCommand(SAVE_COMMAND);
2237            saveItem.addActionListener(this);
2238            result.add(saveItem);
2239            separator = true;
2240        }
2241
2242        if (print) {
2243            if (separator) {
2244                result.addSeparator();
2245                separator = false;
2246            }
2247            JMenuItem JavaDoc printItem = new JMenuItem JavaDoc(
2248                localizationResources.getString("Print...")
2249            );
2250            printItem.setActionCommand(PRINT_COMMAND);
2251            printItem.addActionListener(this);
2252            result.add(printItem);
2253            separator = true;
2254        }
2255
2256        if (zoom) {
2257            if (separator) {
2258                result.addSeparator();
2259                separator = false;
2260            }
2261
2262            JMenu JavaDoc zoomInMenu = new JMenu JavaDoc(
2263                localizationResources.getString("Zoom_In")
2264            );
2265
2266            this.zoomInBothMenuItem = new JMenuItem JavaDoc(
2267                localizationResources.getString("All_Axes")
2268            );
2269            this.zoomInBothMenuItem.setActionCommand(ZOOM_IN_BOTH_COMMAND);
2270            this.zoomInBothMenuItem.addActionListener(this);
2271            zoomInMenu.add(this.zoomInBothMenuItem);
2272
2273            zoomInMenu.addSeparator();
2274
2275            this.zoomInDomainMenuItem = new JMenuItem JavaDoc(
2276                localizationResources.getString("Domain_Axis")
2277            );
2278            this.zoomInDomainMenuItem.setActionCommand(ZOOM_IN_DOMAIN_COMMAND);
2279            this.zoomInDomainMenuItem.addActionListener(this);
2280            zoomInMenu.add(this.zoomInDomainMenuItem);
2281
2282            this.zoomInRangeMenuItem = new JMenuItem JavaDoc(
2283                localizationResources.getString("Range_Axis")
2284            );
2285            this.zoomInRangeMenuItem.setActionCommand(ZOOM_IN_RANGE_COMMAND);
2286            this.zoomInRangeMenuItem.addActionListener(this);
2287            zoomInMenu.add(this.zoomInRangeMenuItem);
2288
2289            result.add(zoomInMenu);
2290
2291            JMenu JavaDoc zoomOutMenu = new JMenu JavaDoc(
2292                localizationResources.getString("Zoom_Out")
2293            );
2294
2295            this.zoomOutBothMenuItem = new JMenuItem JavaDoc(
2296                localizationResources.getString("All_Axes")
2297            );
2298            this.zoomOutBothMenuItem.setActionCommand(ZOOM_OUT_BOTH_COMMAND);
2299            this.zoomOutBothMenuItem.addActionListener(this);
2300            zoomOutMenu.add(this.zoomOutBothMenuItem);
2301
2302            zoomOutMenu.addSeparator();
2303
2304            this.zoomOutDomainMenuItem = new JMenuItem JavaDoc(
2305                localizationResources.getString("Domain_Axis")
2306            );
2307            this.zoomOutDomainMenuItem.setActionCommand(
2308                ZOOM_OUT_DOMAIN_COMMAND
2309            );
2310            this.zoomOutDomainMenuItem.addActionListener(this);
2311            zoomOutMenu.add(this.zoomOutDomainMenuItem);
2312
2313            this.zoomOutRangeMenuItem = new JMenuItem JavaDoc(
2314                localizationResources.getString("Range_Axis")
2315            );
2316            this.zoomOutRangeMenuItem.setActionCommand(ZOOM_OUT_RANGE_COMMAND);
2317            this.zoomOutRangeMenuItem.addActionListener(this);
2318            zoomOutMenu.add(this.zoomOutRangeMenuItem);
2319
2320            result.add(zoomOutMenu);
2321
2322            JMenu JavaDoc autoRangeMenu = new JMenu JavaDoc(
2323                localizationResources.getString("Auto_Range")
2324            );
2325
2326            this.zoomResetBothMenuItem = new JMenuItem JavaDoc(
2327                localizationResources.getString("All_Axes")
2328            );
2329            this.zoomResetBothMenuItem.setActionCommand(
2330                ZOOM_RESET_BOTH_COMMAND
2331            );
2332            this.zoomResetBothMenuItem.addActionListener(this);
2333            autoRangeMenu.add(this.zoomResetBothMenuItem);
2334
2335            autoRangeMenu.addSeparator();
2336            this.zoomResetDomainMenuItem = new JMenuItem JavaDoc(
2337                localizationResources.getString("Domain_Axis")
2338            );
2339            this.zoomResetDomainMenuItem.setActionCommand(
2340                ZOOM_RESET_DOMAIN_COMMAND
2341            );
2342            this.zoomResetDomainMenuItem.addActionListener(this);
2343            autoRangeMenu.add(this.zoomResetDomainMenuItem);
2344
2345            this.zoomResetRangeMenuItem = new JMenuItem JavaDoc(
2346                localizationResources.getString("Range_Axis")
2347            );
2348            this.zoomResetRangeMenuItem.setActionCommand(
2349                ZOOM_RESET_RANGE_COMMAND
2350            );
2351            this.zoomResetRangeMenuItem.addActionListener(this);
2352            autoRangeMenu.add(this.zoomResetRangeMenuItem);
2353
2354            result.addSeparator();
2355            result.add(autoRangeMenu);
2356
2357        }
2358
2359        return result;
2360
2361    }
2362
2363    /**
2364     * The idea is to modify the zooming options depending on the type of chart
2365     * being displayed by the panel.
2366     *
2367     * @param x horizontal position of the popup.
2368     * @param y vertical position of the popup.
2369     */

2370    protected void displayPopupMenu(int x, int y) {
2371
2372        if (this.popup != null) {
2373
2374            // go through each zoom menu item and decide whether or not to
2375
// enable it...
2376
Plot plot = this.chart.getPlot();
2377            boolean isDomainZoomable = false;
2378            boolean isRangeZoomable = false;
2379            if (plot instanceof Zoomable) {
2380                Zoomable z = (Zoomable) plot;
2381                isDomainZoomable = z.isDomainZoomable();
2382                isRangeZoomable = z.isRangeZoomable();
2383            }
2384            
2385            if (this.zoomInDomainMenuItem != null) {
2386                this.zoomInDomainMenuItem.setEnabled(isDomainZoomable);
2387            }
2388            if (this.zoomOutDomainMenuItem != null) {
2389                this.zoomOutDomainMenuItem.setEnabled(isDomainZoomable);
2390            }
2391            if (this.zoomResetDomainMenuItem != null) {
2392                this.zoomResetDomainMenuItem.setEnabled(isDomainZoomable);
2393            }
2394
2395            if (this.zoomInRangeMenuItem != null) {
2396                this.zoomInRangeMenuItem.setEnabled(isRangeZoomable);
2397            }
2398            if (this.zoomOutRangeMenuItem != null) {
2399                this.zoomOutRangeMenuItem.setEnabled(isRangeZoomable);
2400            }
2401
2402            if (this.zoomResetRangeMenuItem != null) {
2403                this.zoomResetRangeMenuItem.setEnabled(isRangeZoomable);
2404            }
2405
2406            if (this.zoomInBothMenuItem != null) {
2407                this.zoomInBothMenuItem.setEnabled(
2408                    isDomainZoomable & isRangeZoomable
2409                );
2410            }
2411            if (this.zoomOutBothMenuItem != null) {
2412                this.zoomOutBothMenuItem.setEnabled(
2413                    isDomainZoomable & isRangeZoomable
2414                );
2415            }
2416            if (this.zoomResetBothMenuItem != null) {
2417                this.zoomResetBothMenuItem.setEnabled(
2418                    isDomainZoomable & isRangeZoomable
2419                );
2420            }
2421
2422            this.popup.show(this, x, y);
2423        }
2424
2425    }
2426
2427}
2428
Popular Tags