001    /* ======================================================
002     * Orson : a free chart beans library based on JFreeChart
003     * ======================================================
004     *
005     * (C) Copyright 2007, by Object Refinery Limited.
006     *
007     * Project Info:  not-yet-released
008     *
009     * This library is free software; you can redistribute it and/or modify it 
010     * under the terms of the GNU Lesser General Public License as published by 
011     * the Free Software Foundation; either version 2.1 of the License, or 
012     * (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but 
015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017     * License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this library; if not, write to the Free Software
021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022     * USA.  
023     *
024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025     * in the United States and other countries.]
026     * 
027     */
028    
029    package org.jfree.beans;
030    
031    import java.awt.Font;
032    import java.awt.Insets;
033    import java.awt.Paint;
034    import java.awt.event.MouseEvent;
035    import java.beans.PropertyChangeEvent;
036    import java.beans.PropertyEditorManager;
037    import java.text.NumberFormat;
038    
039    import org.jfree.beans.editors.AxisScaleEditor;
040    import org.jfree.beans.events.XYItemClickEvent;
041    import org.jfree.beans.events.XYItemClickListener;
042    import org.jfree.chart.axis.AxisLocation;
043    import org.jfree.chart.axis.NumberAxis;
044    import org.jfree.chart.axis.ValueAxis;
045    import org.jfree.chart.entity.ChartEntity;
046    import org.jfree.chart.entity.EntityCollection;
047    import org.jfree.chart.entity.XYItemEntity;
048    import org.jfree.chart.labels.StandardXYToolTipGenerator;
049    import org.jfree.chart.plot.PlotOrientation;
050    import org.jfree.chart.plot.XYPlot;
051    import org.jfree.chart.renderer.xy.XYItemRenderer;
052    
053    /**
054     * A base class for beans that use the {@link XYPlot} class.
055     */
056    public abstract class AbstractXYChart extends AbstractChart {
057        
058        static {
059            PropertyEditorManager.registerEditor(AxisScale.class, 
060                    AxisScaleEditor.class);
061        }
062    
063        /** The scale for the y-axis. */
064        private AxisScale yAxisScale;
065        
066        /**
067         * Creates a new instance.
068         */
069        public AbstractXYChart() {
070            super();
071            this.yAxisScale = AxisScale.FLOAT;
072        }
073        
074        /**
075         * Returns the orientation for the plot.
076         * 
077         * @return The orientation.
078         * 
079         * @see #setOrientation(PlotOrientation)
080         */
081        public PlotOrientation getOrientation() {
082            PlotOrientation result = null;
083            XYPlot plot = (XYPlot) this.chart.getPlot();
084            if (plot != null) {
085                result = plot.getOrientation();
086            }
087            return result;        
088        }
089        
090        /**
091         * Sets the orientation for the plot and fires a 
092         * {@link PropertyChangeEvent} for the <code>orientation</code> property.
093         * 
094         * @param orientation  the orientation (<code>null</code> not permitted).
095         * 
096         * @see #setOrientation(PlotOrientation)
097         */
098        public void setOrientation(PlotOrientation orientation) {
099            XYPlot plot = (XYPlot) this.chart.getPlot();
100            if (plot != null) {
101                PlotOrientation old = plot.getOrientation();
102                plot.setOrientation(orientation);
103                firePropertyChange("orientation", old, orientation);
104            }        
105        }
106        
107        /**
108         * Returns the x-axis label.
109         * 
110         * @return The x-axis label.
111         * 
112         * @see #setXAxisLabel(String)
113         */
114        public String getXAxisLabel() {
115            String result = null;
116            XYPlot plot = (XYPlot) this.chart.getPlot();
117            if (plot != null) {
118                result = plot.getDomainAxis().getLabel();
119            }
120            return result;
121        }
122        
123        /**
124         * Sets the x-axis label and fires a {@link PropertyChangeEvent} for the
125         * <code>xAxisLabel</code> property.
126         * 
127         * @param label  the new label.
128         * 
129         * @see #getXAxisLabel()
130         */
131        public void setXAxisLabel(String label) {
132            XYPlot plot = (XYPlot) this.chart.getPlot();
133            if (plot != null) {
134                ValueAxis axis = plot.getDomainAxis();
135                String old = axis.getLabel();
136                axis.setLabel(label);
137                firePropertyChange("xAxisLabel", old, label);
138            }                
139        }
140        
141        /**
142         * Returns the font for the x-axis label.
143         * 
144         * @return The font for the x-axis label.
145         * 
146         * @see #setXAxisLabelFont(Font)
147         */
148        public Font getXAxisLabelFont() {
149            Font result = null;
150            XYPlot plot = (XYPlot) this.chart.getPlot();
151            if (plot != null) {
152                result = plot.getDomainAxis().getLabelFont();
153            }
154            return result;   
155        }
156        
157        /**
158         * Sets the font for the x-axis label and fires a 
159         * {@link PropertyChangeEvent} for the <code>xAxisLabelFont</code> 
160         * property.
161         * 
162         * @param font  the font (<code>null</code> not permitted).
163         * 
164         * @see #getXAxisLabelFont()
165         */
166        public void setXAxisLabelFont(Font font) {
167            if (font == null) {
168                throw new IllegalArgumentException("Null 'font' argument.");
169            }
170            XYPlot plot = (XYPlot) this.chart.getPlot();
171            if (plot != null) {
172                ValueAxis axis = plot.getDomainAxis();
173                Font old = axis.getLabelFont();
174                axis.setLabelFont(font);
175                firePropertyChange("xAxisLabelFont", old, font);
176            }
177        }
178    
179        /**
180         * Returns the paint for the x-axis label.
181         * 
182         * @return The paint for the x-axis label.
183         * 
184         * @see #setXAxisLabelPaint(Paint)
185         */
186        public Paint getXAxisLabelPaint() {
187            Paint result = null;
188            XYPlot plot = (XYPlot) this.chart.getPlot();
189            if (plot != null) {
190                result = plot.getDomainAxis().getLabelPaint();
191            }
192            return result;   
193        }
194        
195        /**
196         * Sets the paint for the x-axis label and fires a 
197         * {@link PropertyChangeEvent} for the <code>xAxisLabelPaint</code> 
198         * property.
199         * 
200         * @param paint  the paint (<code>null</code> not permitted).
201         * 
202         * @see #getXAxisLabelPaint()
203         */
204        public void setXAxisLabelPaint(Paint paint) {
205            if (paint == null) {
206                throw new IllegalArgumentException("Null 'paint' argument.");
207            }
208            XYPlot plot = (XYPlot) this.chart.getPlot();
209            if (plot != null) {
210                ValueAxis axis = plot.getDomainAxis();
211                Paint old = axis.getLabelPaint();
212                axis.setLabelPaint(paint);
213                firePropertyChange("xAxisLabelPaint", old, paint);
214            }
215        }
216    
217        /**
218         * Returns <code>true</code> if the x-axis is inverted, and 
219         * <code>false</code> otherwise.
220         * 
221         * @return A boolean.
222         * 
223         * @see #setXAxisInverted(boolean)
224         */
225        public boolean isXAxisInverted() {
226            XYPlot plot = (XYPlot) this.chart.getPlot();
227            if (plot != null) {
228                return plot.getDomainAxis().isInverted();
229            }
230            return false;
231        }
232    
233        /**
234         * Sets a flag that controls whether or not the x-axis is inverted and
235         * fires a {@link PropertyChangeEvent} for the <code>xAxisInverted</code>
236         * property.
237         * 
238         * @param inverted  the new flag value.
239         * 
240         * @see #isXAxisInverted()
241         */
242        public void setXAxisInverted(boolean inverted) {
243            XYPlot plot = (XYPlot) this.chart.getPlot();
244            if (plot != null) {
245                ValueAxis axis = plot.getDomainAxis();
246                boolean old = axis.isInverted();
247                axis.setInverted(inverted);
248                firePropertyChange("xAxisInverted", old, inverted);
249            }                
250        }
251        
252        /**
253         * Returns the lower margin for the x-axis.
254         * 
255         * @return The lower margin.
256         * 
257         * @see #setXAxisLowerMargin(double)
258         */
259        public double getXAxisLowerMargin() {
260            XYPlot plot = (XYPlot) this.chart.getPlot();
261            if (plot != null) {
262                return plot.getDomainAxis().getLowerMargin();
263            }
264            return -1.0;
265        }
266        
267        /**
268         * Sets the lower margin for the x-axis and fires a 
269         * {@link PropertyChangeEvent} for the <code>xAxisLowerMargin</code>
270         * property.
271         * 
272         * @param margin  the margin.
273         * 
274         * @see #getXAxisLowerMargin()
275         */
276        public void setXAxisLowerMargin(double margin) {
277            XYPlot plot = (XYPlot) this.chart.getPlot();
278            if (plot != null) {
279                ValueAxis axis = plot.getDomainAxis();
280                double old = axis.getLowerMargin();
281                axis.setLowerMargin(margin);
282                firePropertyChange("xAxisLowerMargin", old, margin);
283            }                
284        }
285        
286        /**
287         * Returns the upper margin for the x-axis.
288         * 
289         * @return The upper margin for the x-axis.
290         * 
291         * @see #setXAxisUpperMargin(double)
292         */
293        public double getXAxisUpperMargin() {
294            XYPlot plot = (XYPlot) this.chart.getPlot();
295            if (plot != null) {
296                return plot.getDomainAxis().getUpperMargin();
297            }
298            return -1.0;
299        }
300    
301        /**
302         * Sets the upper margin for the x-axis and fires a 
303         * {@link PropertyChangeEvent} for the <code>xAxisUpperMargin</code> 
304         * property.
305         * 
306         * @param margin  the margin.
307         * 
308         * @see #getXAxisUpperMargin()
309         */
310        public void setXAxisUpperMargin(double margin) {
311            XYPlot plot = (XYPlot) this.chart.getPlot();
312            if (plot != null) {
313                ValueAxis axis = plot.getDomainAxis();
314                double old = axis.getUpperMargin();
315                axis.setUpperMargin(margin);
316                firePropertyChange("xAxisUpperMargin", old, margin);
317            }                
318        }
319        
320        /**
321         * Returns <code>true</code> if the x-axis gridlines are visible, and 
322         * <code>false</code> otherwise.
323         * 
324         * @return A boolean.
325         * 
326         * @see #setXAxisGridlinesVisible(boolean)
327         */
328        public boolean isXAxisGridlinesVisible() {
329            XYPlot plot = (XYPlot) this.chart.getPlot();
330            if (plot != null) {
331                return plot.isDomainGridlinesVisible();
332            }
333            return false;
334        }
335    
336        /**
337         * Sets a flag that controls whether or not the x-axis gridlines are
338         * drawn and fires a {@link PropertyChangeEvent} for the 
339         * <code>xAxisGridlinesVisible</code> property.
340         * 
341         * @param visible  the new flag value.
342         * 
343         * @see #isXAxisGridlinesVisible()
344         */
345        public void setXAxisGridlinesVisible(boolean visible) {
346            XYPlot plot = (XYPlot) this.chart.getPlot();
347            if (plot != null) {
348                boolean old = plot.isDomainGridlinesVisible();
349                plot.setDomainGridlinesVisible(visible);
350                firePropertyChange("xAxisGridlinesVisible", old, visible);
351            }                
352        }
353        
354        /**
355         * Returns the font for the x-axis tick labels.
356         * 
357         * @return The font for the x-axis tick labels.
358         * 
359         * @see #setXAxisTickLabelFont(Font)
360         */
361        public Font getXAxisTickLabelFont() {
362            Font result = null;
363            XYPlot plot = (XYPlot) this.chart.getPlot();
364            if (plot != null) {
365                result = plot.getDomainAxis().getTickLabelFont();
366            }
367            return result;   
368        }
369        
370        /**
371         * Sets the font for the x-axis tick labels and fires a 
372         * {@link PropertyChangeEvent} for the <code>xAxisTickLabelFont</code>
373         * property.
374         * 
375         * @param font  the font (<code>null</code> not permitted).
376         * 
377         * @see #getXAxisTickLabelFont()
378         */
379        public void setXAxisTickLabelFont(Font font) {
380            if (font == null) {
381                throw new IllegalArgumentException("Null 'font' argument.");
382            }
383            XYPlot plot = (XYPlot) this.chart.getPlot();
384            if (plot != null) {
385                ValueAxis axis = plot.getDomainAxis();
386                Font old = axis.getTickLabelFont();
387                axis.setTickLabelFont(font);
388                firePropertyChange("xAxisTickLabelFont", old, font);
389            }
390        }
391    
392        /**
393         * Returns the paint for the x-axis tick labels.
394         * 
395         * @return The paint for the x-axis tick labels.
396         * 
397         * @see #setXAxisTickLabelPaint(Paint)
398         */
399        public Paint getXAxisTickLabelPaint() {
400            Paint result = null;
401            XYPlot plot = (XYPlot) this.chart.getPlot();
402            if (plot != null) {
403                result = plot.getDomainAxis().getTickLabelPaint();
404            }
405            return result;   
406        }
407        
408        /**
409         * Sets the paint for the x-axis tick labels and fires a 
410         * {@link PropertyChangeEvent} for the <code>xAxisTickLabelPaint</code>
411         * property.
412         * 
413         * @param paint  the paint (<code>null</code> not permitted).
414         * 
415         * @see #getXAxisTickLabelPaint()
416         */
417        public void setXAxisTickLabelPaint(Paint paint) {
418            if (paint == null) {
419                throw new IllegalArgumentException("Null 'paint' argument.");
420            }
421            XYPlot plot = (XYPlot) this.chart.getPlot();
422            if (plot != null) {
423                ValueAxis axis = plot.getDomainAxis();
424                Paint old = axis.getTickLabelPaint();
425                axis.setTickLabelPaint(paint);
426                firePropertyChange("xAxisTickLabelPaint", old, paint);
427            }
428        }
429        
430        /**
431         * Returns the y-axis label.
432         * 
433         * @return The y-axis label.
434         * 
435         * @see #setYAxisLabel(String)
436         */
437        public String getYAxisLabel() {
438            String result = null;
439            XYPlot plot = (XYPlot) this.chart.getPlot();
440            if (plot != null) {
441                result = plot.getRangeAxis().getLabel();
442            }
443            return result;
444        }
445        
446        /**
447         * Sets the y-axis label and fires a {@link PropertyChangeEvent} for the
448         * <code>yAxisLabel</code> property.
449         * 
450         * @param label  the label.
451         * 
452         * @see #getYAxisLabel()
453         */
454        public void setYAxisLabel(String label) {
455            XYPlot plot = (XYPlot) this.chart.getPlot();
456            if (plot != null) {
457                ValueAxis axis = plot.getRangeAxis();
458                String old = axis.getLabel();
459                axis.setLabel(label);
460                firePropertyChange("yAxisLabel", old, label);
461            }                
462        }
463    
464        /**
465         * Returns the font for the y-axis label.
466         * 
467         * @return The font for the y-axis label.
468         * 
469         * @see #setYAxisLabelFont(Font)
470         */
471        public Font getYAxisLabelFont() {
472            Font result = null;
473            XYPlot plot = (XYPlot) this.chart.getPlot();
474            if (plot != null) {
475                result = plot.getRangeAxis().getLabelFont();
476            }
477            return result;   
478        }
479        
480        /**
481         * Sets the font for the y-axis label and fires a 
482         * {@link PropertyChangeEvent} for the <code>yAxisLabelFont</code>
483         * property.
484         * 
485         * @param font  the font (<code>null</code> not permitted).
486         * 
487         * @see #getYAxisLabelFont()
488         */
489        public void setYAxisLabelFont(Font font) {
490            if (font == null) {
491                throw new IllegalArgumentException("Null 'font' argument.");
492            }
493            XYPlot plot = (XYPlot) this.chart.getPlot();
494            if (plot != null) {
495                ValueAxis axis = plot.getRangeAxis();
496                Font old = axis.getLabelFont();
497                axis.setLabelFont(font);
498                firePropertyChange("yAxisLabelFont", old, font);
499            }
500        }
501    
502        /**
503         * Returns the paint for the y-axis label.
504         * 
505         * @return The paint for the y-axis label.
506         * 
507         * @see #setYAxisLabelPaint(Paint)
508         */
509        public Paint getYAxisLabelPaint() {
510            Paint result = null;
511            XYPlot plot = (XYPlot) this.chart.getPlot();
512            if (plot != null) {
513                result = plot.getRangeAxis().getLabelPaint();
514            }
515            return result;   
516        }
517        
518        /**
519         * Sets the paint for the y-axis label and fires a 
520         * {@link PropertyChangeEvent} for the <code>yAxisLabelPaint</code> 
521         * property.
522         * 
523         * @param paint  the paint (<code>null</code> not permitted).
524         * 
525         * @see #getYAxisLabelPaint()
526         */
527        public void setYAxisLabelPaint(Paint paint) {
528            if (paint == null) {
529                throw new IllegalArgumentException("Null 'paint' argument.");
530            }
531            XYPlot plot = (XYPlot) this.chart.getPlot();
532            if (plot != null) {
533                ValueAxis axis = plot.getRangeAxis();
534                Paint old = axis.getLabelPaint();
535                axis.setLabelPaint(paint);
536                firePropertyChange("yAxisLabelPaint", old, paint);
537            }
538        }
539        
540        /**
541         * Returns the scale type for the y-axis.
542         * 
543         * @return The scale type.
544         * 
545         * @see #setYAxisScale(AxisScale)
546         */
547        public AxisScale getYAxisScale() {
548            return this.yAxisScale;
549        }
550    
551        /**
552         * Sets the scale type for the y-axis and fires a 
553         * {@link PropertyChangeEvent} for the <code>yAxisScale</code> property.
554         * 
555         * @param scale  the scale type.
556         * 
557         * @see #getYAxisScale()
558         */
559        public void setYAxisScale(AxisScale scale) {
560            XYPlot plot = (XYPlot) this.chart.getPlot();
561            if (plot != null) {
562                AxisScale old = this.yAxisScale;
563                ValueAxis axis = plot.getRangeAxis();
564                if (AxisScale.INTEGER.equals(scale)) {
565                    axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
566                }
567                else if (AxisScale.FLOAT.equals(scale)) {
568                    axis.setStandardTickUnits(NumberAxis.createStandardTickUnits());
569                }
570    
571                firePropertyChange("yAxisScale", old, scale);
572            }
573        }
574        
575        /**
576         * Returns <code>true</code> if the y-axis is inverted, and 
577         * <code>false</code> otherwise.
578         * 
579         * @return A boolean.
580         * 
581         * @see #setYAxisInverted(boolean)
582         */
583        public boolean isYAxisInverted() {
584            XYPlot plot = (XYPlot) this.chart.getPlot();
585            if (plot != null) {
586                return plot.getRangeAxis().isInverted();
587            }
588            return false;
589        }
590    
591        /**
592         * Sets a flag that controls whether or not the y-axis is inverted and
593         * fires a {@link PropertyChangeEvent} for the <code>yAxisInverted</code>
594         * property.
595         * 
596         * @param inverted  the new flag value.
597         * 
598         * @see #isYAxisInverted()
599         */
600        public void setYAxisInverted(boolean inverted) {
601            XYPlot plot = (XYPlot) this.chart.getPlot();
602            if (plot != null) {
603                ValueAxis axis = plot.getRangeAxis();
604                boolean old = axis.isInverted();
605                axis.setInverted(inverted);
606                firePropertyChange("yAxisInverted", old, inverted);
607            }                
608        }
609        
610        /**
611         * Returns the flag that controls whether or not the auto range calculation
612         * is forced to include zero.
613         * 
614         * @return A boolean.
615         * 
616         * @see #setYAxisAutoRangeIncludesZero(boolean)
617         */
618        public boolean getYAxisAutoRangeIncludesZero() {
619            XYPlot plot = (XYPlot) this.chart.getPlot();
620            if (plot == null) {
621                return false;
622            }
623            NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
624            return yAxis.getAutoRangeIncludesZero();
625        }
626        
627        /**
628         * Sets the flag that controls whether or not the auto range calculation
629         * is forced to include zero, and fires a {@link PropertyChangeEvent} 
630         * for the <code>yAxisAutoRangeIncludesZero</code> property.
631         * 
632         * @param include  the new flag value.
633         * 
634         * @see #getYAxisAutoRangeIncludesZero()
635         */
636        public void setYAxisAutoRangeIncludesZero(boolean include) {
637            XYPlot plot = (XYPlot) this.chart.getPlot();
638            if (plot == null) {
639                return;
640            }
641            NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
642            boolean old = yAxis.getAutoRangeIncludesZero();
643            yAxis.setAutoRangeIncludesZero(include);
644            firePropertyChange("yAxisAutoRangeIncludesZero", old, include);
645        }
646    
647        /**
648         * Returns the lower margin for the y-axis.
649         * 
650         * @return The lower margin.
651         * 
652         * @see #setYAxisLowerMargin(double)
653         */
654        public double getYAxisLowerMargin() {
655            XYPlot plot = (XYPlot) this.chart.getPlot();
656            if (plot != null) {
657                return plot.getRangeAxis().getLowerMargin();
658            }
659            return -1.0;
660        }
661        
662        /**
663         * Sets the lower margin for the y-axis and fires a 
664         * {@link PropertyChangeEvent} for the <code>yAxisLowerMargin</code>
665         * property.
666         * 
667         * @param margin  the margin.
668         * 
669         * @see #getYAxisLowerMargin()
670         */
671        public void setYAxisLowerMargin(double margin) {
672            XYPlot plot = (XYPlot) this.chart.getPlot();
673            if (plot != null) {
674                ValueAxis axis = plot.getRangeAxis();
675                double old = axis.getLowerMargin();
676                axis.setLowerMargin(margin);
677                firePropertyChange("yAxisLowerMargin", old, margin);
678            }                
679        }
680        
681        /**
682         * Returns the upper margin for the y-axis.
683         * 
684         * @return The upper margin for the y-axis.
685         * 
686         * @see #setYAxisUpperMargin(double)
687         */
688        public double getYAxisUpperMargin() {
689            XYPlot plot = (XYPlot) this.chart.getPlot();
690            if (plot != null) {
691                return plot.getRangeAxis().getUpperMargin();
692            }
693            return -1.0;
694        }
695    
696        /**
697         * Sets the upper margin for the y-axis and fires a 
698         * {@link PropertyChangeEvent} for the <code>yAxisUpperMargin</code> 
699         * property.
700         * 
701         * @param margin  the margin.
702         * 
703         * @see #getYAxisUpperMargin()
704         */
705        public void setYAxisUpperMargin(double margin) {
706            XYPlot plot = (XYPlot) this.chart.getPlot();
707            if (plot != null) {
708                ValueAxis axis = plot.getRangeAxis();
709                double old = axis.getUpperMargin();
710                axis.setUpperMargin(margin);
711                firePropertyChange("yAxisUpperMargin", old, margin);
712            }                
713        }
714        
715        /**
716         * Returns <code>true</code> if the y-axis gridlines are visible, and 
717         * <code>false</code> otherwise.
718         * 
719         * @return A boolean.
720         * 
721         * @see #setYAxisGridlinesVisible(boolean)
722         */
723        public boolean isYAxisGridlinesVisible() {
724            XYPlot plot = (XYPlot) this.chart.getPlot();
725            if (plot != null) {
726                return plot.isRangeGridlinesVisible();
727            }
728            return false;
729        }
730    
731        /**
732         * Sets a flag that controls whether or not the y-axis gridlines are
733         * drawn and fires a {@link PropertyChangeEvent} for the
734         * <code>yAxisGridlinesVisible</code> property.
735         * 
736         * @param visible  the new flag value.
737         * 
738         * @see #isYAxisGridlinesVisible()
739         */
740        public void setYAxisGridlinesVisible(boolean visible) {
741            XYPlot plot = (XYPlot) this.chart.getPlot();
742            if (plot != null) {
743                boolean old = plot.isRangeGridlinesVisible();
744                plot.setRangeGridlinesVisible(visible);
745                firePropertyChange("yAxisGridlinesVisible", old, visible);
746            }                
747        }
748        
749        /**
750         * Returns the grid line paint for the gridlines perpendicular to the
751         * x-axis.
752         * 
753         * @return The paint.
754         * 
755         * @see #setXAxisGridlinePaint(Paint)
756         */
757        public Paint getXAxisGridlinePaint() {
758            XYPlot plot = (XYPlot) this.chart.getPlot();
759            if (plot != null) {
760                return plot.getDomainGridlinePaint();
761            }
762            return null;
763        }
764        
765        /**
766         * Sets the paint for the x-axis gridlines and fires a 
767         * {@link PropertyChangeEvent} for the <code>xAxisGridlinePaint</code>
768         * property.
769         * 
770         * @param paint  the paint.
771         * 
772         * @see #getXAxisGridlinePaint()
773         */
774        public void setXAxisGridlinePaint(Paint paint) {
775            XYPlot plot = (XYPlot) this.chart.getPlot();
776            if (plot != null) {
777                Paint old = plot.getDomainGridlinePaint();
778                plot.setDomainGridlinePaint(paint);
779                firePropertyChange("xAxisGridlinePaint", old, paint);
780            }
781        }
782        
783        /**
784         * Returns the y-axis gridline paint.
785         * 
786         * @return The y-axis gridline paint.
787         * 
788         * @see #setYAxisGridlinePaint(Paint)
789         */
790        public Paint getYAxisGridlinePaint() {
791            XYPlot plot = (XYPlot) this.chart.getPlot();
792            if (plot != null) {
793                return plot.getRangeGridlinePaint();
794            }
795            return null;
796        }
797        
798        /**
799         * Sets the y-axis gridline paint and fires a {@link PropertyChangeEvent}
800         * for the <code>yAxisGridlinePaint</code> property.
801         * 
802         * @param paint  the paint.
803         * 
804         * @see #getYAxisGridlinePaint()
805         */
806        public void setYAxisGridlinePaint(Paint paint) {
807            XYPlot plot = (XYPlot) this.chart.getPlot();
808            if (plot != null) {
809                Paint old = plot.getRangeGridlinePaint();
810                plot.setRangeGridlinePaint(paint);
811                firePropertyChange("yAxisGridlinePaint", old, paint);
812            }
813        }
814        
815        /**
816         * Returns the font for the y-axis tick labels.
817         * 
818         * @return The font for the y-axis tick labels.
819         * 
820         * @see #setYAxisTickLabelFont(Font)
821         */
822        public Font getYAxisTickLabelFont() {
823            Font result = null;
824            XYPlot plot = (XYPlot) this.chart.getPlot();
825            if (plot != null) {
826                result = plot.getRangeAxis().getTickLabelFont();
827            }
828            return result;   
829        }
830        
831        /**
832         * Sets the font for the y-axis tick labels and fires a 
833         * {@link PropertyChangeEvent} for the <code>yAxisTickLabelFont</code>
834         * property.
835         * 
836         * @param font  the font (<code>null</code> not permitted).
837         * 
838         * @see #getYAxisTickLabelFont()
839         */
840        public void setYAxisTickLabelFont(Font font) {
841            if (font == null) {
842                throw new IllegalArgumentException("Null 'font' argument.");
843            }
844            XYPlot plot = (XYPlot) this.chart.getPlot();
845            if (plot != null) {
846                ValueAxis axis = plot.getRangeAxis();
847                Font old = axis.getTickLabelFont();
848                axis.setTickLabelFont(font);
849                firePropertyChange("yAxisTickLabelFont", old, font);
850            }
851        }
852    
853        /**
854         * Returns the paint for the y-axis tick labels.
855         * 
856         * @return The paint for the y-axis tick labels.
857         * 
858         * @see #setYAxisTickLabelPaint(Paint)
859         */
860        public Paint getYAxisTickLabelPaint() {
861            Paint result = null;
862            XYPlot plot = (XYPlot) this.chart.getPlot();
863            if (plot != null) {
864                result = plot.getRangeAxis().getTickLabelPaint();
865            }
866            return result;   
867        }
868        
869        /**
870         * Sets the paint for the y-axis tick labels and fires a 
871         * {@link PropertyChangeEvent} for the <code>yAxisTickLabelPaint</code>
872         * property.
873         * 
874         * @param paint  the paint (<code>null</code> not permitted).
875         * 
876         * @see #getYAxisTickLabelPaint()
877         */
878        public void setYAxisTickLabelPaint(Paint paint) {
879            if (paint == null) {
880                throw new IllegalArgumentException("Null 'paint' argument.");
881            }
882            XYPlot plot = (XYPlot) this.chart.getPlot();
883            if (plot != null) {
884                ValueAxis axis = plot.getRangeAxis();
885                Paint old = axis.getTickLabelPaint();
886                axis.setTickLabelPaint(paint);
887                firePropertyChange("yAxisTickLabelPaint", old, paint);
888            }
889        }
890        
891        /**
892         * Returns the permitted axis locations for the x-axis.
893         * 
894         * @return The axis location.
895         * 
896         * @see #setXAxisLocation(AxisLocation)
897         */
898        public AxisLocation getXAxisLocation() {
899            XYPlot plot = (XYPlot) this.chart.getPlot();
900            if (plot != null) {
901                return plot.getDomainAxisLocation();
902            }
903            return null;                
904        }
905        
906        /**
907         * Sets the axis location for the x-axis and fires a 
908         * {@link PropertyChangeEvent} for the <code>xAxisLocation</code> argument.
909         * 
910         * @param location  the location (<code>null</code> not permitted).
911         * 
912         * @see #getXAxisLocation()
913         */
914        public void setXAxisLocation(AxisLocation location) {
915            if (location == null) {
916                throw new IllegalArgumentException("Null 'location' argument.");
917            }
918            XYPlot plot = (XYPlot) this.chart.getPlot();
919            if (plot != null) {
920                AxisLocation old = plot.getDomainAxisLocation();
921                plot.setDomainAxisLocation(location);
922                firePropertyChange("xAxisLocation", old, location);
923            }
924        }
925        
926        /**
927         * Returns the permitted axis locations for the y-axis.
928         * 
929         * @return The axis location.
930         * 
931         * @see #setYAxisLocation(AxisLocation)
932         */
933        public AxisLocation getYAxisLocation() {
934            XYPlot plot = (XYPlot) this.chart.getPlot();
935            if (plot != null) {
936                return plot.getRangeAxisLocation();
937            }
938            return null;                
939        }
940        
941        /**
942         * Sets the axis location for the y-axis and fires a 
943         * {@link PropertyChangeEvent} for the <code>yAxisLocation</code>
944         * property.
945         * 
946         * @param location  the location (<code>null</code> not permitted).
947         * 
948         * @see #getYAxisLocation()
949         */
950        public void setYAxisLocation(AxisLocation location) {
951            if (location == null) {
952                throw new IllegalArgumentException("Null 'location' argument.");
953            }
954            XYPlot plot = (XYPlot) this.chart.getPlot();
955            if (plot != null) {
956                AxisLocation old = plot.getRangeAxisLocation();
957                plot.setRangeAxisLocation(location);
958                firePropertyChange("yAxisLocation", old, location);
959            }
960        }
961        
962        /**
963         * Returns the format string for the item tool tips.
964         * 
965         * @return The format string.
966         * 
967         * @see #setToolTipFormat(String)
968         */
969        public String getToolTipFormat() {
970            XYPlot p = (XYPlot) this.chart.getPlot();
971            if (p == null) {
972                return "";
973            }
974            XYItemRenderer r = p.getRenderer();
975            if (r == null) {
976                return "";
977            }
978            StandardXYToolTipGenerator g = (StandardXYToolTipGenerator) 
979                    r.getBaseToolTipGenerator();
980            if (g == null) {
981                return "";
982            }
983            return g.getFormatString();
984        }
985        
986        /**
987         * Sets the format string for the section tool tips and fires a 
988         * {@link PropertyChangeEvent} for the <code>toolTipFormat</code> property.
989         * 
990         * @param format  the format string.
991         * 
992         * @see #getToolTipFormat()
993         */
994        public void setToolTipFormat(String format) {
995            XYPlot p = (XYPlot) this.chart.getPlot();
996            if (p == null) {
997                return;
998            }
999            XYItemRenderer r = p.getRenderer();
1000            if (r == null) {
1001                return;
1002            }
1003            if (format.equals("")) {
1004                r.setBaseToolTipGenerator(null);
1005            }
1006            else {
1007                r.setBaseToolTipGenerator(new StandardXYToolTipGenerator(format, 
1008                        NumberFormat.getInstance(), NumberFormat.getInstance()));   
1009            }
1010            // FIXME: what to use for the oldValue
1011            firePropertyChange("toolTipFormat", null, format);
1012        }
1013        
1014        /**
1015         * Returns a flag that controls whether or not an arrow-head is displayed
1016         * at the positive end of the x-axis.
1017         * 
1018         * @return A boolean.
1019         * 
1020         * @see #setXAxisPositiveArrowVisible(boolean)
1021         */
1022        public boolean isXAxisPositiveArrowVisible() {
1023            XYPlot plot = (XYPlot) this.chart.getPlot();
1024            if (plot != null) {
1025                return plot.getDomainAxis().isPositiveArrowVisible();
1026            }
1027            return false;                
1028        }
1029        
1030        /**
1031         * Sets the flag that controls whether or not an arrow-head is displayed
1032         * at the positive end of the y-axis and fires a {@link PropertyChangeEvent} 
1033         * for the <code>yAxisPositiveArrowVisible</code> property.
1034         * 
1035         * @param visible  the new flag value.
1036         * 
1037         * @see #isYAxisPositiveArrowVisible()
1038         */
1039        public void setXAxisPositiveArrowVisible(boolean visible) {
1040            XYPlot plot = (XYPlot) this.chart.getPlot();
1041            if (plot != null) {
1042                ValueAxis axis = plot.getDomainAxis();
1043                boolean old = axis.isPositiveArrowVisible();
1044                axis.setPositiveArrowVisible(visible);
1045                firePropertyChange("xAxisPositiveArrowVisible", old, visible);
1046            }                
1047        }
1048    
1049        /**
1050         * Returns a flag that controls whether or not an arrow-head is displayed
1051         * at the negative end of the x-axis.
1052         * 
1053         * @return A boolean.
1054         * 
1055         * @see #setXAxisNegativeArrowVisible(boolean)
1056         */
1057        public boolean isXAxisNegativeArrowVisible() {
1058            XYPlot plot = (XYPlot) this.chart.getPlot();
1059            if (plot != null) {
1060                return plot.getDomainAxis().isNegativeArrowVisible();
1061            }
1062            return false;                
1063        }
1064        
1065        /**
1066         * Sets the flag that controls whether or not an arrow-head is displayed
1067         * at the negative end of the x-axis and fires a {@link PropertyChangeEvent} 
1068         * for the <code>xAxisNegativeArrowVisible</code> property.
1069         * 
1070         * @param visible  the new flag value.
1071         * 
1072         * @see #isXAxisNegativeArrowVisible()
1073         */
1074        public void setXAxisNegativeArrowVisible(boolean visible) {
1075            XYPlot plot = (XYPlot) this.chart.getPlot();
1076            if (plot != null) {
1077                ValueAxis axis = plot.getDomainAxis();
1078                boolean old = axis.isNegativeArrowVisible();
1079                axis.setNegativeArrowVisible(visible);
1080                firePropertyChange("xAxisNegativeArrowVisible", old, visible);
1081            }                
1082        }
1083    
1084        /**
1085         * Returns a flag that controls whether or not an arrow-head is displayed
1086         * at the positive end of the y-axis.
1087         * 
1088         * @return A boolean.
1089         * 
1090         * @see #setYAxisPositiveArrowVisible(boolean)
1091         */
1092        public boolean isYAxisPositiveArrowVisible() {
1093            XYPlot plot = (XYPlot) this.chart.getPlot();
1094            if (plot != null) {
1095                return plot.getRangeAxis().isPositiveArrowVisible();
1096            }
1097            return false;                
1098        }
1099        
1100        /**
1101         * Sets the flag that controls whether or not an arrow-head is displayed
1102         * at the positive end of the y-axis and fires a {@link PropertyChangeEvent} 
1103         * for the <code>yAxisPositiveArrowVisible</code> property.
1104         * 
1105         * @param visible  the new flag value.
1106         * 
1107         * @see #isYAxisPositiveArrowVisible()
1108         */
1109        public void setYAxisPositiveArrowVisible(boolean visible) {
1110            XYPlot plot = (XYPlot) this.chart.getPlot();
1111            if (plot != null) {
1112                ValueAxis axis = plot.getRangeAxis();
1113                boolean old = axis.isPositiveArrowVisible();
1114                axis.setPositiveArrowVisible(visible);
1115                firePropertyChange("yAxisPositiveArrowVisible", old, visible);
1116            }                
1117        }
1118    
1119        /**
1120         * Returns a flag that controls whether or not an arrow-head is displayed
1121         * at the negative end of the y-axis.
1122         * 
1123         * @return A boolean.
1124         * 
1125         * @see #setYAxisNegativeArrowVisible(boolean)
1126         */
1127        public boolean isYAxisNegativeArrowVisible() {
1128            XYPlot plot = (XYPlot) this.chart.getPlot();
1129            if (plot != null) {
1130                return plot.getRangeAxis().isNegativeArrowVisible();
1131            }
1132            return false;                
1133        }
1134        
1135        /**
1136         * Sets the flag that controls whether or not an arrow-head is displayed
1137         * at the negative end of the y-axis and fires a {@link PropertyChangeEvent} 
1138         * for the <code>yAxisNegativeArrowVisible</code> property.
1139         * 
1140         * @param visible  the new flag value.
1141         * 
1142         * @see #isYAxisNegativeArrowVisible()
1143         */
1144        public void setYAxisNegativeArrowVisible(boolean visible) {
1145            XYPlot plot = (XYPlot) this.chart.getPlot();
1146            if (plot != null) {
1147                ValueAxis axis = plot.getRangeAxis();
1148                boolean old = axis.isNegativeArrowVisible();
1149                axis.setNegativeArrowVisible(visible);
1150                firePropertyChange("yAxisNegativeArrowVisible", old, visible);
1151            }                
1152        }
1153    
1154        /**
1155         * Registers a listener to receive notification of category item clicks.
1156         * 
1157         * @param listener  the listener (<code>null</code> not permitted).
1158         */
1159        public void addXYItemClickListener(XYItemClickListener listener) {
1160            if (listener == null) {
1161                throw new IllegalArgumentException("Null 'listener' argument.");
1162            }
1163            this.listeners.add(XYItemClickListener.class, listener);
1164        }
1165        
1166        /**
1167         * Unregisters a listener so that it no longer receives notification of 
1168         * category item clicks.
1169         * 
1170         * @param listener  the listener (<code>null</code> not permitted).
1171         */
1172        public void removeXYItemClickListener(XYItemClickListener listener) {
1173            if (listener == null) {
1174                throw new IllegalArgumentException("Null 'listener' argument.");
1175            }
1176            this.listeners.remove(XYItemClickListener.class, listener);        
1177        }
1178        
1179        /**
1180         * Fires a category item click event.
1181         * 
1182         * @param event  the event.
1183         */
1184        public void fireXYItemClickEvent(XYItemClickEvent event) {
1185            Object[] listeners = this.listeners.getListeners(
1186                    XYItemClickListener.class);
1187            for (int i = listeners.length - 1; i >= 0; i -= 1) {
1188                ((XYItemClickListener) listeners[i]).onXYItemClick(event);
1189            }                
1190            
1191        }
1192        
1193        /**
1194         * If the user clicks on the chart, see if that translates into an event
1195         * that we report...
1196         * 
1197         * @param event  the event.
1198         */
1199        public void mouseClicked(MouseEvent event) {
1200            // if no-one is listening, just return...
1201            Object[] listeners = this.listeners.getListeners(
1202                    XYItemClickListener.class);
1203            if (listeners.length == 0) {
1204                super.mouseClicked(event);
1205            }
1206    
1207            Insets insets = getInsets();
1208            int x = event.getX() - insets.left;
1209            int y = event.getY() - insets.top;
1210    
1211            ChartEntity entity = null;
1212            if (this.info != null) {
1213                EntityCollection entities = this.info.getEntityCollection();
1214                if (entities != null) {
1215                    entity = entities.getEntity(x, y);
1216                }
1217            }
1218            if (entity instanceof XYItemEntity) {
1219                XYItemEntity xyie = (XYItemEntity) entity;
1220                XYItemClickEvent lce = new XYItemClickEvent(this, 
1221                        xyie.getDataset(), xyie.getSeriesIndex(), xyie.getItem());
1222                fireXYItemClickEvent(lce);
1223            }
1224            else {
1225                super.mouseClicked(event);
1226            }
1227            
1228        }
1229    
1230    }