001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2009, by Object Refinery Limited and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
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 * StandardChartTheme.java
029 * -----------------------
030 * (C) Copyright 2008, 2009, by Object Refinery Limited.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 * Changes
036 * -------
037 * 14-Aug-2008 : Version 1 (DG);
038 * 10-Apr-2009 : Added getter/setter for smallFont (DG);
039 *
040 */
041
042package org.jfree.chart;
043
044import java.awt.BasicStroke;
045import java.awt.Color;
046import java.awt.Font;
047import java.awt.Paint;
048import java.awt.Stroke;
049import java.io.IOException;
050import java.io.ObjectInputStream;
051import java.io.ObjectOutputStream;
052import java.io.Serializable;
053import java.util.Iterator;
054import java.util.List;
055
056import org.jfree.chart.annotations.XYAnnotation;
057import org.jfree.chart.annotations.XYTextAnnotation;
058import org.jfree.chart.axis.CategoryAxis;
059import org.jfree.chart.axis.PeriodAxis;
060import org.jfree.chart.axis.PeriodAxisLabelInfo;
061import org.jfree.chart.axis.SubCategoryAxis;
062import org.jfree.chart.axis.SymbolAxis;
063import org.jfree.chart.axis.ValueAxis;
064import org.jfree.chart.block.Block;
065import org.jfree.chart.block.BlockContainer;
066import org.jfree.chart.block.LabelBlock;
067import org.jfree.chart.plot.CategoryPlot;
068import org.jfree.chart.plot.CombinedDomainCategoryPlot;
069import org.jfree.chart.plot.CombinedDomainXYPlot;
070import org.jfree.chart.plot.CombinedRangeCategoryPlot;
071import org.jfree.chart.plot.CombinedRangeXYPlot;
072import org.jfree.chart.plot.DefaultDrawingSupplier;
073import org.jfree.chart.plot.DrawingSupplier;
074import org.jfree.chart.plot.FastScatterPlot;
075import org.jfree.chart.plot.MeterPlot;
076import org.jfree.chart.plot.MultiplePiePlot;
077import org.jfree.chart.plot.PieLabelLinkStyle;
078import org.jfree.chart.plot.PiePlot;
079import org.jfree.chart.plot.Plot;
080import org.jfree.chart.plot.PolarPlot;
081import org.jfree.chart.plot.SpiderWebPlot;
082import org.jfree.chart.plot.ThermometerPlot;
083import org.jfree.chart.plot.XYPlot;
084import org.jfree.chart.renderer.AbstractRenderer;
085import org.jfree.chart.renderer.category.BarPainter;
086import org.jfree.chart.renderer.category.BarRenderer;
087import org.jfree.chart.renderer.category.BarRenderer3D;
088import org.jfree.chart.renderer.category.CategoryItemRenderer;
089import org.jfree.chart.renderer.category.GradientBarPainter;
090import org.jfree.chart.renderer.category.LineRenderer3D;
091import org.jfree.chart.renderer.category.MinMaxCategoryRenderer;
092import org.jfree.chart.renderer.category.StatisticalBarRenderer;
093import org.jfree.chart.renderer.xy.GradientXYBarPainter;
094import org.jfree.chart.renderer.xy.XYBarPainter;
095import org.jfree.chart.renderer.xy.XYBarRenderer;
096import org.jfree.chart.renderer.xy.XYItemRenderer;
097import org.jfree.chart.title.CompositeTitle;
098import org.jfree.chart.title.LegendTitle;
099import org.jfree.chart.title.PaintScaleLegend;
100import org.jfree.chart.title.TextTitle;
101import org.jfree.chart.title.Title;
102import org.jfree.io.SerialUtilities;
103import org.jfree.ui.RectangleInsets;
104import org.jfree.util.PaintUtilities;
105import org.jfree.util.PublicCloneable;
106
107/**
108 * A default implementation of the {@link ChartTheme} interface.  This
109 * implementation just collects a whole bunch of chart attributes and mimics
110 * the manual process of applying each attribute to the right sub-object
111 * within the JFreeChart instance.  It's not elegant code, but it works.
112 *
113 * @since 1.0.11
114 */
115public class StandardChartTheme implements ChartTheme, Cloneable,
116        PublicCloneable, Serializable {
117
118    /** The name of this theme. */
119    private String name;
120
121    /**
122     * The largest font size.  Use for the main chart title.
123     */
124    private Font extraLargeFont;
125
126    /**
127     * A large font.  Used for subtitles.
128     */
129    private Font largeFont;
130
131    /**
132     * The regular font size.  Used for axis tick labels, legend items etc.
133     */
134    private Font regularFont;
135
136    /**
137     * The small font size.
138     */
139    private Font smallFont;
140
141    /** The paint used to display the main chart title. */
142    private transient Paint titlePaint;
143
144    /** The paint used to display subtitles. */
145    private transient Paint subtitlePaint;
146
147    /** The background paint for the chart. */
148    private transient Paint chartBackgroundPaint;
149
150    /** The legend background paint. */
151    private transient Paint legendBackgroundPaint;
152
153    /** The legend item paint. */
154    private transient Paint legendItemPaint;
155
156    /** The drawing supplier. */
157    private DrawingSupplier drawingSupplier;
158
159    /** The background paint for the plot. */
160    private transient Paint plotBackgroundPaint;
161
162    /** The plot outline paint. */
163    private transient Paint plotOutlinePaint;
164
165    /** The label link style for pie charts. */
166    private PieLabelLinkStyle labelLinkStyle;
167
168    /** The label link paint for pie charts. */
169    private transient Paint labelLinkPaint;
170
171    /** The domain grid line paint. */
172    private transient Paint domainGridlinePaint;
173
174    /** The range grid line paint. */
175    private transient Paint rangeGridlinePaint;
176
177    /** 
178     * The baseline paint (used for domain and range zero baselines)
179     * 
180     * @since 1.0.13
181     */
182    private transient Paint baselinePaint;
183
184    /** The crosshair paint. */
185    private transient Paint crosshairPaint;
186
187    /** The axis offsets. */
188    private RectangleInsets axisOffset;
189
190    /** The axis label paint. */
191    private transient Paint axisLabelPaint;
192
193    /** The tick label paint. */
194    private transient Paint tickLabelPaint;
195
196    /** The item label paint. */
197    private transient Paint itemLabelPaint;
198
199    /**
200     * A flag that controls whether or not shadows are visible (for example,
201     * in a bar renderer).
202     */
203    private boolean shadowVisible;
204
205    /** The shadow paint. */
206    private transient Paint shadowPaint;
207
208    /** The bar painter. */
209    private BarPainter barPainter;
210
211    /** The XY bar painter. */
212    private XYBarPainter xyBarPainter;
213
214    /** The thermometer paint. */
215    private transient Paint thermometerPaint;
216
217    /**
218     * The paint used to fill the interior of the 'walls' in the background
219     * of a plot with a 3D effect.  Applied to BarRenderer3D.
220     */
221    private transient Paint wallPaint;
222
223    /** The error indicator paint for the {@link StatisticalBarRenderer}. */
224    private transient Paint errorIndicatorPaint;
225
226    /** The grid band paint for a {@link SymbolAxis}. */
227    private transient Paint gridBandPaint = SymbolAxis.DEFAULT_GRID_BAND_PAINT;
228
229    /** The grid band alternate paint for a {@link SymbolAxis}. */
230    private transient Paint gridBandAlternatePaint
231            = SymbolAxis.DEFAULT_GRID_BAND_ALTERNATE_PAINT;
232
233    /**
234     * Creates and returns the default 'JFree' chart theme.
235     *
236     * @return A chart theme.
237     */
238    public static ChartTheme createJFreeTheme() {
239        return new StandardChartTheme("JFree");
240    }
241
242    /**
243     * Creates and returns a theme called "Darkness".  In this theme, the
244     * charts have a black background.
245     *
246     * @return The "Darkness" theme.
247     */
248    public static ChartTheme createDarknessTheme() {
249        StandardChartTheme theme = new StandardChartTheme("Darkness");
250        theme.titlePaint = Color.white;
251        theme.subtitlePaint = Color.white;
252        theme.legendBackgroundPaint = Color.black;
253        theme.legendItemPaint = Color.white;
254        theme.chartBackgroundPaint = Color.black;
255        theme.plotBackgroundPaint = Color.black;
256        theme.plotOutlinePaint = Color.yellow;
257        theme.baselinePaint = Color.white;
258        theme.crosshairPaint = Color.red;
259        theme.labelLinkPaint = Color.lightGray;
260        theme.tickLabelPaint = Color.white;
261        theme.axisLabelPaint = Color.white;
262        theme.shadowPaint = Color.darkGray;
263        theme.itemLabelPaint = Color.white;
264        theme.drawingSupplier = new DefaultDrawingSupplier(
265                new Paint[] {Color.decode("0xFFFF00"),
266                        Color.decode("0x0036CC"), Color.decode("0xFF0000"),
267                        Color.decode("0xFFFF7F"), Color.decode("0x6681CC"),
268                        Color.decode("0xFF7F7F"), Color.decode("0xFFFFBF"),
269                        Color.decode("0x99A6CC"), Color.decode("0xFFBFBF"),
270                        Color.decode("0xA9A938"), Color.decode("0x2D4587")},
271                new Paint[] {Color.decode("0xFFFF00"),
272                        Color.decode("0x0036CC")},
273                new Stroke[] {new BasicStroke(2.0f)},
274                new Stroke[] {new BasicStroke(0.5f)},
275                DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE);
276        theme.wallPaint = Color.darkGray;
277        theme.errorIndicatorPaint = Color.lightGray;
278        theme.gridBandPaint = new Color(255, 255, 255, 20);
279        theme.gridBandAlternatePaint = new Color(255, 255, 255, 40);
280        return theme;
281    }
282    /**
283     * Creates and returns a {@link ChartTheme} that doesn't apply any changes
284     * to the JFreeChart defaults.  This produces the "legacy" look for
285     * JFreeChart.
286     *
287     * @return A legacy theme.
288     */
289    public static ChartTheme createLegacyTheme() {
290        StandardChartTheme theme = new StandardChartTheme("Legacy") {
291            public void apply(JFreeChart chart) {
292                // do nothing at all
293            }
294        };
295        return theme;
296    }
297
298    /**
299     * Creates a new default instance.
300     *
301     * @param name  the name of the theme (<code>null</code> not permitted).
302     */
303    public StandardChartTheme(String name) {
304        if (name == null) {
305            throw new IllegalArgumentException("Null 'name' argument.");
306        }
307        this.name = name;
308        this.extraLargeFont = new Font("Tahoma", Font.BOLD, 20);
309        this.largeFont = new Font("Tahoma", Font.BOLD, 14);
310        this.regularFont = new Font("Tahoma", Font.PLAIN, 12);
311        this.smallFont = new Font("Tahoma", Font.PLAIN, 10);
312        this.titlePaint = Color.black;
313        this.subtitlePaint = Color.black;
314        this.legendBackgroundPaint = Color.white;
315        this.legendItemPaint = Color.darkGray;
316        this.chartBackgroundPaint = Color.white;
317        this.drawingSupplier = new DefaultDrawingSupplier();
318        this.plotBackgroundPaint = Color.lightGray;
319        this.plotOutlinePaint = Color.black;
320        this.labelLinkPaint = Color.black;
321        this.labelLinkStyle = PieLabelLinkStyle.CUBIC_CURVE;
322        this.axisOffset = new RectangleInsets(4, 4, 4, 4);
323        this.domainGridlinePaint = Color.white;
324        this.rangeGridlinePaint = Color.white;
325        this.baselinePaint = Color.black;
326        this.crosshairPaint = Color.blue;
327        this.axisLabelPaint = Color.darkGray;
328        this.tickLabelPaint = Color.darkGray;
329        this.barPainter = new GradientBarPainter();
330        this.xyBarPainter = new GradientXYBarPainter();
331        this.shadowVisible = true;
332        this.shadowPaint = Color.gray;
333        this.itemLabelPaint = Color.black;
334        this.thermometerPaint = Color.white;
335        this.wallPaint = BarRenderer3D.DEFAULT_WALL_PAINT;
336        this.errorIndicatorPaint = Color.black;
337    }
338
339    /**
340     * Returns the largest font for this theme.
341     *
342     * @return The largest font for this theme.
343     *
344     * @see #setExtraLargeFont(Font)
345     */
346    public Font getExtraLargeFont() {
347        return this.extraLargeFont;
348    }
349
350    /**
351     * Sets the largest font for this theme.
352     *
353     * @param font  the font (<code>null</code> not permitted).
354     *
355     * @see #getExtraLargeFont()
356     */
357    public void setExtraLargeFont(Font font) {
358        if (font == null) {
359            throw new IllegalArgumentException("Null 'font' argument.");
360        }
361        this.extraLargeFont = font;
362    }
363
364    /**
365     * Returns the large font for this theme.
366     *
367     * @return The large font (never <code>null</code>).
368     *
369     * @see #setLargeFont(Font)
370     */
371    public Font getLargeFont() {
372        return this.largeFont;
373    }
374
375    /**
376     * Sets the large font for this theme.
377     *
378     * @param font  the font (<code>null</code> not permitted).
379     *
380     * @see #getLargeFont()
381     */
382    public void setLargeFont(Font font) {
383        if (font == null) {
384            throw new IllegalArgumentException("Null 'font' argument.");
385        }
386        this.largeFont = font;
387    }
388
389    /**
390     * Returns the regular font.
391     *
392     * @return The regular font (never <code>null</code>).
393     *
394     * @see #setRegularFont(Font)
395     */
396    public Font getRegularFont() {
397        return this.regularFont;
398    }
399
400    /**
401     * Sets the regular font for this theme.
402     *
403     * @param font  the font (<code>null</code> not permitted).
404     *
405     * @see #getRegularFont()
406     */
407    public void setRegularFont(Font font) {
408        if (font == null) {
409            throw new IllegalArgumentException("Null 'font' argument.");
410        }
411        this.regularFont = font;
412    }
413
414    /**
415     * Returns the small font.
416     *
417     * @return The small font (never <code>null</code>).
418     *
419     * @see #setSmallFont(Font)
420     *
421     * @since 1.0.13
422     */
423    public Font getSmallFont() {
424        return this.smallFont;
425    }
426
427    /**
428     * Sets the small font for this theme.
429     *
430     * @param font  the font (<code>null</code> not permitted).
431     *
432     * @see #getSmallFont()
433     *
434     * @since 1.0.13
435     */
436    public void setSmallFont(Font font) {
437        if (font == null) {
438            throw new IllegalArgumentException("Null 'font' argument.");
439        }
440        this.smallFont = font;
441    }
442
443    /**
444     * Returns the title paint.
445     *
446     * @return The title paint (never <code>null</code>).
447     *
448     * @see #setTitlePaint(Paint)
449     */
450    public Paint getTitlePaint() {
451        return this.titlePaint;
452    }
453
454    /**
455     * Sets the title paint.
456     *
457     * @param paint  the paint (<code>null</code> not permitted).
458     *
459     * @see #getTitlePaint()
460     */
461    public void setTitlePaint(Paint paint) {
462        if (paint == null) {
463            throw new IllegalArgumentException("Null 'paint' argument.");
464        }
465        this.titlePaint = paint;
466    }
467
468    /**
469     * Returns the subtitle paint.
470     *
471     * @return The subtitle paint (never <code>null</code>).
472     *
473     * @see #setSubtitlePaint(Paint)
474     */
475    public Paint getSubtitlePaint() {
476        return this.subtitlePaint;
477    }
478
479    /**
480     * Sets the subtitle paint.
481     *
482     * @param paint  the paint (<code>null</code> not permitted).
483     *
484     * @see #getSubtitlePaint()
485     */
486    public void setSubtitlePaint(Paint paint) {
487        if (paint == null) {
488            throw new IllegalArgumentException("Null 'paint' argument.");
489        }
490        this.subtitlePaint = paint;
491    }
492
493    /**
494     * Returns the chart background paint.
495     *
496     * @return The chart background paint (never <code>null</code>).
497     *
498     * @see #setChartBackgroundPaint(Paint)
499     */
500    public Paint getChartBackgroundPaint() {
501        return this.chartBackgroundPaint;
502    }
503
504    /**
505     * Sets the chart background paint.
506     *
507     * @param paint  the paint (<code>null</code> not permitted).
508     *
509     * @see #getChartBackgroundPaint()
510     */
511    public void setChartBackgroundPaint(Paint paint) {
512        if (paint == null) {
513            throw new IllegalArgumentException("Null 'paint' argument.");
514        }
515        this.chartBackgroundPaint = paint;
516    }
517
518    /**
519     * Returns the legend background paint.
520     *
521     * @return The legend background paint (never <code>null</code>).
522     *
523     * @see #setLegendBackgroundPaint(Paint)
524     */
525    public Paint getLegendBackgroundPaint() {
526        return this.legendBackgroundPaint;
527    }
528
529    /**
530     * Sets the legend background paint.
531     *
532     * @param paint  the paint (<code>null</code> not permitted).
533     *
534     * @see #getLegendBackgroundPaint()
535     */
536    public void setLegendBackgroundPaint(Paint paint) {
537        if (paint == null) {
538            throw new IllegalArgumentException("Null 'paint' argument.");
539        }
540        this.legendBackgroundPaint = paint;
541    }
542
543    /**
544     * Returns the legend item paint.
545     *
546     * @return The legend item paint (never <code>null</code>).
547     *
548     * @see #setLegendItemPaint(Paint)
549     */
550    public Paint getLegendItemPaint() {
551        return this.legendItemPaint;
552    }
553
554    /**
555     * Sets the legend item paint.
556     *
557     * @param paint  the paint (<code>null</code> not permitted).
558     *
559     * @see #getLegendItemPaint()
560     */
561    public void setLegendItemPaint(Paint paint) {
562        if (paint == null) {
563            throw new IllegalArgumentException("Null 'paint' argument.");
564        }
565        this.legendItemPaint = paint;
566    }
567
568    /**
569     * Returns the plot background paint.
570     *
571     * @return The plot background paint (never <code>null</code>).
572     *
573     * @see #setPlotBackgroundPaint(Paint)
574     */
575    public Paint getPlotBackgroundPaint() {
576        return this.plotBackgroundPaint;
577    }
578
579    /**
580     * Sets the plot background paint.
581     *
582     * @param paint  the paint (<code>null</code> not permitted).
583     *
584     * @see #getPlotBackgroundPaint()
585     */
586    public void setPlotBackgroundPaint(Paint paint) {
587        if (paint == null) {
588            throw new IllegalArgumentException("Null 'paint' argument.");
589        }
590        this.plotBackgroundPaint = paint;
591    }
592
593    /**
594     * Returns the plot outline paint.
595     *
596     * @return The plot outline paint (never <code>null</code>).
597     *
598     * @see #setPlotOutlinePaint(Paint)
599     */
600    public Paint getPlotOutlinePaint() {
601        return this.plotOutlinePaint;
602    }
603
604    /**
605     * Sets the plot outline paint.
606     *
607     * @param paint  the paint (<code>null</code> not permitted).
608     *
609     * @see #getPlotOutlinePaint()
610     */
611    public void setPlotOutlinePaint(Paint paint) {
612        if (paint == null) {
613            throw new IllegalArgumentException("Null 'paint' argument.");
614        }
615        this.plotOutlinePaint = paint;
616    }
617
618    /**
619     * Returns the label link style for pie charts.
620     *
621     * @return The label link style (never <code>null</code>).
622     *
623     * @see #setLabelLinkStyle(PieLabelLinkStyle)
624     */
625    public PieLabelLinkStyle getLabelLinkStyle() {
626        return this.labelLinkStyle;
627    }
628
629    /**
630     * Sets the label link style for pie charts.
631     *
632     * @param style  the style (<code>null</code> not permitted).
633     *
634     * @see #getLabelLinkStyle()
635     */
636    public void setLabelLinkStyle(PieLabelLinkStyle style) {
637        if (style == null) {
638            throw new IllegalArgumentException("Null 'style' argument.");
639        }
640        this.labelLinkStyle = style;
641    }
642
643    /**
644     * Returns the label link paint for pie charts.
645     *
646     * @return The label link paint (never <code>null</code>).
647     *
648     * @see #setLabelLinkPaint(Paint)
649     */
650    public Paint getLabelLinkPaint() {
651        return this.labelLinkPaint;
652    }
653
654    /**
655     * Sets the label link paint for pie charts.
656     *
657     * @param paint  the paint (<code>null</code> not permitted).
658     *
659     * @see #getLabelLinkPaint()
660     */
661    public void setLabelLinkPaint(Paint paint) {
662        if (paint == null) {
663            throw new IllegalArgumentException("Null 'paint' argument.");
664        }
665        this.labelLinkPaint = paint;
666    }
667
668    /**
669     * Returns the domain grid line paint.
670     *
671     * @return The domain grid line paint (never <code>null<code>).
672     *
673     * @see #setDomainGridlinePaint(Paint)
674     */
675    public Paint getDomainGridlinePaint() {
676        return this.domainGridlinePaint;
677    }
678
679    /**
680     * Sets the domain grid line paint.
681     *
682     * @param paint  the paint (<code>null</code> not permitted).
683     *
684     * @see #getDomainGridlinePaint()
685     */
686    public void setDomainGridlinePaint(Paint paint) {
687        if (paint == null) {
688            throw new IllegalArgumentException("Null 'paint' argument.");
689        }
690        this.domainGridlinePaint = paint;
691    }
692
693    /**
694     * Returns the range grid line paint.
695     *
696     * @return The range grid line paint (never <code>null</code>).
697     *
698     * @see #setRangeGridlinePaint(Paint)
699     */
700    public Paint getRangeGridlinePaint() {
701        return this.rangeGridlinePaint;
702    }
703
704    /**
705     * Sets the range grid line paint.
706     *
707     * @param paint  the paint (<code>null</code> not permitted).
708     *
709     * @see #getRangeGridlinePaint()
710     */
711    public void setRangeGridlinePaint(Paint paint) {
712        if (paint == null) {
713            throw new IllegalArgumentException("Null 'paint' argument.");
714        }
715        this.rangeGridlinePaint = paint;
716    }
717
718    /**
719     * Returns the baseline paint.
720     * 
721     * @return The baseline paint.
722     * 
723     * @since 1.0.13
724     */
725    public Paint getBaselinePaint() {
726        return this.baselinePaint;
727    }
728
729    /**
730     * Sets the baseline paint.
731     *
732     * @param paint  the paint (<code>null</code> not permitted).
733     *
734     * @since 1.0.13
735     */
736    public void setBaselinePaint(Paint paint) {
737        if (paint == null) {
738            throw new IllegalArgumentException("Null 'paint' argument.");
739        }
740        this.baselinePaint = paint;
741    }
742
743    /**
744     * Returns the crosshair paint.
745     *
746     * @return The crosshair paint.
747     */
748    public Paint getCrosshairPaint() {
749        return this.crosshairPaint;
750    }
751
752    /**
753     * Sets the crosshair paint.
754     *
755     * @param paint  the paint (<code>null</code> not permitted).
756     */
757    public void setCrosshairPaint(Paint paint) {
758        if (paint == null) {
759            throw new IllegalArgumentException("Null 'paint' argument.");
760        }
761        this.crosshairPaint = paint;
762    }
763
764    /**
765     * Returns the axis offsets.
766     *
767     * @return The axis offsets (never <code>null</code>).
768     *
769     * @see #setAxisOffset(RectangleInsets)
770     */
771    public RectangleInsets getAxisOffset() {
772        return this.axisOffset;
773    }
774
775    /**
776     * Sets the axis offset.
777     *
778     * @param offset  the offset (<code>null</code> not permitted).
779     *
780     * @see #getAxisOffset()
781     */
782    public void setAxisOffset(RectangleInsets offset) {
783        if (offset == null) {
784            throw new IllegalArgumentException("Null 'offset' argument.");
785        }
786        this.axisOffset = offset;
787    }
788
789    /**
790     * Returns the axis label paint.
791     *
792     * @return The axis label paint (never <code>null</code>).
793     *
794     * @see #setAxisLabelPaint(Paint)
795     */
796    public Paint getAxisLabelPaint() {
797        return this.axisLabelPaint;
798    }
799
800    /**
801     * Sets the axis label paint.
802     *
803     * @param paint  the paint (<code>null</code> not permitted).
804     *
805     * @see #getAxisLabelPaint()
806     */
807    public void setAxisLabelPaint(Paint paint) {
808        if (paint == null) {
809            throw new IllegalArgumentException("Null 'paint' argument.");
810        }
811        this.axisLabelPaint = paint;
812    }
813
814    /**
815     * Returns the tick label paint.
816     *
817     * @return The tick label paint (never <code>null</code>).
818     *
819     * @see #setTickLabelPaint(Paint)
820     */
821    public Paint getTickLabelPaint() {
822        return this.tickLabelPaint;
823    }
824
825    /**
826     * Sets the tick label paint.
827     *
828     * @param paint  the paint (<code>null</code> not permitted).
829     *
830     * @see #getTickLabelPaint()
831     */
832    public void setTickLabelPaint(Paint paint) {
833        if (paint == null) {
834            throw new IllegalArgumentException("Null 'paint' argument.");
835        }
836        this.tickLabelPaint = paint;
837    }
838
839    /**
840     * Returns the item label paint.
841     *
842     * @return The item label paint (never <code>null</code>).
843     *
844     * @see #setItemLabelPaint(Paint)
845     */
846    public Paint getItemLabelPaint() {
847        return this.itemLabelPaint;
848    }
849
850    /**
851     * Sets the item label paint.
852     *
853     * @param paint  the paint (<code>null</code> not permitted).
854     *
855     * @see #getItemLabelPaint()
856     */
857    public void setItemLabelPaint(Paint paint) {
858        if (paint == null) {
859            throw new IllegalArgumentException("Null 'paint' argument.");
860        }
861        this.itemLabelPaint = paint;
862    }
863
864    /**
865     * Returns the shadow visibility flag.
866     *
867     * @return The shadow visibility flag.
868     *
869     * @see #setShadowVisible(boolean)
870     */
871    public boolean isShadowVisible() {
872        return this.shadowVisible;
873    }
874
875    /**
876     * Sets the shadow visibility flag.
877     *
878     * @param visible  the flag.
879     *
880     * @see #isShadowVisible()
881     */
882    public void setShadowVisible(boolean visible) {
883        this.shadowVisible = visible;
884    }
885
886    /**
887     * Returns the shadow paint.
888     *
889     * @return The shadow paint (never <code>null</code>).
890     *
891     * @see #setShadowPaint(Paint)
892     */
893    public Paint getShadowPaint() {
894        return this.shadowPaint;
895    }
896
897    /**
898     * Sets the shadow paint.
899     *
900     * @param paint  the paint (<code>null</code> not permitted).
901     *
902     * @see #getShadowPaint()
903     */
904    public void setShadowPaint(Paint paint) {
905        if (paint == null) {
906            throw new IllegalArgumentException("Null 'paint' argument.");
907        }
908        this.shadowPaint = paint;
909    }
910
911    /**
912     * Returns the bar painter.
913     *
914     * @return The bar painter (never <code>null</code>).
915     *
916     * @see #setBarPainter(BarPainter)
917     */
918    public BarPainter getBarPainter() {
919        return this.barPainter;
920    }
921
922    /**
923     * Sets the bar painter.
924     *
925     * @param painter  the painter (<code>null</code> not permitted).
926     *
927     * @see #getBarPainter()
928     */
929    public void setBarPainter(BarPainter painter) {
930        if (painter == null) {
931            throw new IllegalArgumentException("Null 'painter' argument.");
932        }
933        this.barPainter = painter;
934    }
935
936    /**
937     * Returns the XY bar painter.
938     *
939     * @return The XY bar painter (never <code>null</code>).
940     *
941     * @see #setXYBarPainter(XYBarPainter)
942     */
943    public XYBarPainter getXYBarPainter() {
944        return this.xyBarPainter;
945    }
946
947    /**
948     * Sets the XY bar painter.
949     *
950     * @param painter  the painter (<code>null</code> not permitted).
951     *
952     * @see #getXYBarPainter()
953     */
954    public void setXYBarPainter(XYBarPainter painter) {
955        if (painter == null) {
956            throw new IllegalArgumentException("Null 'painter' argument.");
957        }
958        this.xyBarPainter = painter;
959    }
960
961    /**
962     * Returns the thermometer paint.
963     *
964     * @return The thermometer paint (never <code>null</code>).
965     *
966     * @see #setThermometerPaint(Paint)
967     */
968    public Paint getThermometerPaint() {
969        return this.thermometerPaint;
970    }
971
972    /**
973     * Sets the thermometer paint.
974     *
975     * @param paint  the paint (<code>null</code> not permitted).
976     *
977     * @see #getThermometerPaint()
978     */
979    public void setThermometerPaint(Paint paint) {
980        if (paint == null) {
981            throw new IllegalArgumentException("Null 'paint' argument.");
982        }
983        this.thermometerPaint = paint;
984    }
985
986    /**
987     * Returns the wall paint for charts with a 3D effect.
988     *
989     * @return The wall paint (never <code>null</code>).
990     *
991     * @see #setWallPaint(Paint)
992     */
993    public Paint getWallPaint() {
994        return this.wallPaint;
995    }
996
997    /**
998     * Sets the wall paint for charts with a 3D effect.
999     *
1000     * @param paint  the paint (<code>null</code> not permitted).
1001     *
1002     * @see #getWallPaint()
1003     */
1004    public void setWallPaint(Paint paint) {
1005        if (paint == null) {
1006            throw new IllegalArgumentException("Null 'paint' argument.");
1007        }
1008        this.wallPaint = paint;
1009    }
1010
1011    /**
1012     * Returns the error indicator paint.
1013     *
1014     * @return The error indicator paint (never <code>null</code>).
1015     *
1016     * @see #setErrorIndicatorPaint(Paint)
1017     */
1018    public Paint getErrorIndicatorPaint() {
1019        return this.errorIndicatorPaint;
1020    }
1021
1022    /**
1023     * Sets the error indicator paint.
1024     *
1025     * @param paint  the paint (<code>null</code> not permitted).
1026     *
1027     * @see #getErrorIndicatorPaint()
1028     */
1029    public void setErrorIndicatorPaint(Paint paint) {
1030        if (paint == null) {
1031            throw new IllegalArgumentException("Null 'paint' argument.");
1032        }
1033        this.errorIndicatorPaint = paint;
1034    }
1035
1036    /**
1037     * Returns the grid band paint.
1038     *
1039     * @return The grid band paint (never <code>null</code>).
1040     *
1041     * @see #setGridBandPaint(Paint)
1042     */
1043    public Paint getGridBandPaint() {
1044        return this.gridBandPaint;
1045    }
1046
1047    /**
1048     * Sets the grid band paint.
1049     *
1050     * @param paint  the paint (<code>null</code> not permitted).
1051     *
1052     * @see #getGridBandPaint()
1053     */
1054    public void setGridBandPaint(Paint paint) {
1055        if (paint == null) {
1056            throw new IllegalArgumentException("Null 'paint' argument.");
1057        }
1058        this.gridBandPaint = paint;
1059    }
1060
1061    /**
1062     * Returns the grid band alternate paint (used for a {@link SymbolAxis}).
1063     *
1064     * @return The paint (never <code>null</code>).
1065     *
1066     * @see #setGridBandAlternatePaint(Paint)
1067     */
1068    public Paint getGridBandAlternatePaint() {
1069        return this.gridBandAlternatePaint;
1070    }
1071
1072    /**
1073     * Sets the grid band alternate paint (used for a {@link SymbolAxis}).
1074     *
1075     * @param paint  the paint (<code>null</code> not permitted).
1076     *
1077     * @see #getGridBandAlternatePaint()
1078     */
1079    public void setGridBandAlternatePaint(Paint paint) {
1080        if (paint == null) {
1081            throw new IllegalArgumentException("Null 'paint' argument.");
1082        }
1083        this.gridBandAlternatePaint = paint;
1084    }
1085
1086    /**
1087     * Returns the name of this theme.
1088     *
1089     * @return The name of this theme.
1090     */
1091    public String getName() {
1092        return this.name;
1093    }
1094
1095    /**
1096     * Returns a clone of the drawing supplier for this theme.
1097     *
1098     * @return A clone of the drawing supplier.
1099     */
1100    public DrawingSupplier getDrawingSupplier() {
1101        DrawingSupplier result = null;
1102        if (this.drawingSupplier instanceof PublicCloneable) {
1103            PublicCloneable pc = (PublicCloneable) this.drawingSupplier;
1104              try {
1105                result = (DrawingSupplier) pc.clone();
1106            }
1107            catch (CloneNotSupportedException e) {
1108                e.printStackTrace();
1109            }
1110        }
1111        return result;
1112    }
1113
1114    /**
1115     * Sets the drawing supplier for this theme.
1116     *
1117     * @param supplier  the supplier (<code>null</code> not permitted).
1118     *
1119     * @see #getDrawingSupplier()
1120     */
1121    public void setDrawingSupplier(DrawingSupplier supplier) {
1122        if (supplier == null) {
1123            throw new IllegalArgumentException("Null 'supplier' argument.");
1124        }
1125        this.drawingSupplier = supplier;
1126    }
1127
1128    /**
1129     * Applies this theme to the supplied chart.
1130     *
1131     * @param chart  the chart (<code>null</code> not permitted).
1132     */
1133    public void apply(JFreeChart chart) {
1134        if (chart == null) {
1135            throw new IllegalArgumentException("Null 'chart' argument.");
1136        }
1137        TextTitle title = chart.getTitle();
1138        if (title != null) {
1139            title.setFont(this.extraLargeFont);
1140            title.setPaint(this.titlePaint);
1141        }
1142
1143        int subtitleCount = chart.getSubtitleCount();
1144        for (int i = 0; i < subtitleCount; i++) {
1145            applyToTitle(chart.getSubtitle(i));
1146        }
1147
1148        chart.setBackgroundPaint(this.chartBackgroundPaint);
1149
1150        // now process the plot if there is one
1151        Plot plot = chart.getPlot();
1152        if (plot != null) {
1153            applyToPlot(plot);
1154        }
1155    }
1156
1157    /**
1158     * Applies the attributes of this theme to the specified title.
1159     *
1160     * @param title  the title.
1161     */
1162    protected void applyToTitle(Title title) {
1163        if (title instanceof TextTitle) {
1164            TextTitle tt = (TextTitle) title;
1165            tt.setFont(this.largeFont);
1166            tt.setPaint(this.subtitlePaint);
1167        }
1168        else if (title instanceof LegendTitle) {
1169            LegendTitle lt = (LegendTitle) title;
1170            if (lt.getBackgroundPaint() != null) {
1171                lt.setBackgroundPaint(this.legendBackgroundPaint);
1172            }
1173            lt.setItemFont(this.regularFont);
1174            lt.setItemPaint(this.legendItemPaint);
1175            if (lt.getWrapper() != null) {
1176                applyToBlockContainer(lt.getWrapper());
1177            }
1178        }
1179        else if (title instanceof PaintScaleLegend) {
1180            PaintScaleLegend psl = (PaintScaleLegend) title;
1181            psl.setBackgroundPaint(this.legendBackgroundPaint);
1182            ValueAxis axis = psl.getAxis();
1183            if (axis != null) {
1184                applyToValueAxis(axis);
1185            }
1186        }
1187        else if (title instanceof CompositeTitle) {
1188            CompositeTitle ct = (CompositeTitle) title;
1189            BlockContainer bc = ct.getContainer();
1190            List blocks = bc.getBlocks();
1191            Iterator iterator = blocks.iterator();
1192            while (iterator.hasNext()) {
1193                Block b = (Block) iterator.next();
1194                if (b instanceof Title) {
1195                    applyToTitle((Title) b);
1196                }
1197            }
1198        }
1199    }
1200
1201    /**
1202     * Applies the attributes of this theme to the specified container.
1203     *
1204     * @param bc  a block container (<code>null</code> not permitted).
1205     */
1206    protected void applyToBlockContainer(BlockContainer bc) {
1207        Iterator iterator = bc.getBlocks().iterator();
1208        while (iterator.hasNext()) {
1209            Block b = (Block) iterator.next();
1210            applyToBlock(b);
1211        }
1212    }
1213
1214    /**
1215     * Applies the attributes of this theme to the specified block.
1216     *
1217     * @param b  the block.
1218     */
1219    protected void applyToBlock(Block b) {
1220        if (b instanceof Title) {
1221            applyToTitle((Title) b);
1222        }
1223        else if (b instanceof LabelBlock) {
1224            LabelBlock lb = (LabelBlock) b;
1225            lb.setFont(this.regularFont);
1226            lb.setPaint(this.legendItemPaint);
1227        }
1228    }
1229
1230    /**
1231     * Applies the attributes of this theme to a plot.
1232     *
1233     * @param plot  the plot (<code>null</code>).
1234     */
1235    protected void applyToPlot(Plot plot) {
1236        if (plot == null) {
1237            throw new IllegalArgumentException("Null 'plot' argument.");
1238        }
1239        if (plot.getDrawingSupplier() != null) {
1240            plot.setDrawingSupplier(getDrawingSupplier());
1241        }
1242        if (plot.getBackgroundPaint() != null) {
1243            plot.setBackgroundPaint(this.plotBackgroundPaint);
1244        }
1245        plot.setOutlinePaint(this.plotOutlinePaint);
1246
1247        // now handle specific plot types (and yes, I know this is some
1248        // really ugly code that has to be manually updated any time a new
1249        // plot type is added - I should have written something much cooler,
1250        // but I didn't and neither did anyone else).
1251        if (plot instanceof PiePlot) {
1252            applyToPiePlot((PiePlot) plot);
1253        }
1254        else if (plot instanceof MultiplePiePlot) {
1255            applyToMultiplePiePlot((MultiplePiePlot) plot);
1256        }
1257        else if (plot instanceof CategoryPlot) {
1258            applyToCategoryPlot((CategoryPlot) plot);
1259        }
1260        else if (plot instanceof XYPlot) {
1261            applyToXYPlot((XYPlot) plot);
1262        }
1263        else if (plot instanceof FastScatterPlot) {
1264            applyToFastScatterPlot((FastScatterPlot) plot);
1265        }
1266        else if (plot instanceof MeterPlot) {
1267            applyToMeterPlot((MeterPlot) plot);
1268        }
1269        else if (plot instanceof ThermometerPlot) {
1270            applyToThermometerPlot((ThermometerPlot) plot);
1271        }
1272        else if (plot instanceof SpiderWebPlot) {
1273            applyToSpiderWebPlot((SpiderWebPlot) plot);
1274        }
1275        else if (plot instanceof PolarPlot) {
1276            applyToPolarPlot((PolarPlot) plot);
1277        }
1278    }
1279
1280    /**
1281     * Applies the attributes of this theme to a {@link PiePlot} instance.
1282     * This method also clears any set values for the section paint, outline
1283     * etc, so that the theme's {@link DrawingSupplier} will be used.
1284     *
1285     * @param plot  the plot (<code>null</code> not permitted).
1286     */
1287    protected void applyToPiePlot(PiePlot plot) {
1288        plot.setLabelLinkPaint(this.labelLinkPaint);
1289        plot.setLabelLinkStyle(this.labelLinkStyle);
1290        plot.setLabelFont(this.regularFont);
1291
1292        // clear the section attributes so that the theme's DrawingSupplier
1293        // will be used
1294        if (plot.getAutoPopulateSectionPaint()) {
1295            plot.clearSectionPaints(false);
1296        }
1297        if (plot.getAutoPopulateSectionOutlinePaint()) {
1298            plot.clearSectionOutlinePaints(false);
1299        }
1300        if (plot.getAutoPopulateSectionOutlineStroke()) {
1301            plot.clearSectionOutlineStrokes(false);
1302        }
1303    }
1304
1305    /**
1306     * Applies the attributes of this theme to a {@link MultiplePiePlot}.
1307     *
1308     * @param plot  the plot (<code>null</code> not permitted).
1309     */
1310    protected void applyToMultiplePiePlot(MultiplePiePlot plot) {
1311        apply(plot.getPieChart());
1312    }
1313
1314    /**
1315     * Applies the attributes of this theme to a {@link CategoryPlot}.
1316     *
1317     * @param plot  the plot (<code>null</code> not permitted).
1318     */
1319    protected void applyToCategoryPlot(CategoryPlot plot) {
1320        plot.setAxisOffset(this.axisOffset);
1321        plot.setDomainGridlinePaint(this.domainGridlinePaint);
1322        plot.setRangeGridlinePaint(this.rangeGridlinePaint);
1323        plot.setRangeZeroBaselinePaint(this.baselinePaint);
1324
1325        // process all domain axes
1326        int domainAxisCount = plot.getDomainAxisCount();
1327        for (int i = 0; i < domainAxisCount; i++) {
1328            CategoryAxis axis = plot.getDomainAxis(i);
1329            if (axis != null) {
1330                applyToCategoryAxis(axis);
1331            }
1332        }
1333
1334        // process all range axes
1335        int rangeAxisCount = plot.getRangeAxisCount();
1336        for (int i = 0; i < rangeAxisCount; i++) {
1337            ValueAxis axis = (ValueAxis) plot.getRangeAxis(i);
1338            if (axis != null) {
1339                applyToValueAxis(axis);
1340            }
1341        }
1342
1343        // process all renderers
1344        int rendererCount = plot.getRendererCount();
1345        for (int i = 0; i < rendererCount; i++) {
1346            CategoryItemRenderer r = plot.getRenderer(i);
1347            if (r != null) {
1348                applyToCategoryItemRenderer(r);
1349            }
1350        }
1351
1352        if (plot instanceof CombinedDomainCategoryPlot) {
1353            CombinedDomainCategoryPlot cp = (CombinedDomainCategoryPlot) plot;
1354            Iterator iterator = cp.getSubplots().iterator();
1355            while (iterator.hasNext()) {
1356                CategoryPlot subplot = (CategoryPlot) iterator.next();
1357                if (subplot != null) {
1358                    applyToPlot(subplot);
1359                }
1360            }
1361        }
1362        if (plot instanceof CombinedRangeCategoryPlot) {
1363            CombinedRangeCategoryPlot cp = (CombinedRangeCategoryPlot) plot;
1364            Iterator iterator = cp.getSubplots().iterator();
1365            while (iterator.hasNext()) {
1366                CategoryPlot subplot = (CategoryPlot) iterator.next();
1367                if (subplot != null) {
1368                    applyToPlot(subplot);
1369                }
1370            }
1371        }
1372    }
1373
1374    /**
1375     * Applies the attributes of this theme to a {@link XYPlot}.
1376     *
1377     * @param plot  the plot (<code>null</code> not permitted).
1378     */
1379    protected void applyToXYPlot(XYPlot plot) {
1380        plot.setAxisOffset(this.axisOffset);
1381        plot.setDomainZeroBaselinePaint(this.baselinePaint);
1382        plot.setRangeZeroBaselinePaint(this.baselinePaint);
1383        plot.setDomainGridlinePaint(this.domainGridlinePaint);
1384        plot.setRangeGridlinePaint(this.rangeGridlinePaint);
1385        plot.setDomainCrosshairPaint(this.crosshairPaint);
1386        plot.setRangeCrosshairPaint(this.crosshairPaint);
1387        // process all domain axes
1388        int domainAxisCount = plot.getDomainAxisCount();
1389        for (int i = 0; i < domainAxisCount; i++) {
1390            ValueAxis axis = plot.getDomainAxis(i);
1391            if (axis != null) {
1392                applyToValueAxis(axis);
1393            }
1394        }
1395
1396        // process all range axes
1397        int rangeAxisCount = plot.getRangeAxisCount();
1398        for (int i = 0; i < rangeAxisCount; i++) {
1399            ValueAxis axis = (ValueAxis) plot.getRangeAxis(i);
1400            if (axis != null) {
1401                applyToValueAxis(axis);
1402            }
1403        }
1404
1405        // process all renderers
1406        int rendererCount = plot.getRendererCount();
1407        for (int i = 0; i < rendererCount; i++) {
1408            XYItemRenderer r = plot.getRenderer(i);
1409            if (r != null) {
1410                applyToXYItemRenderer(r);
1411            }
1412        }
1413
1414        // process all annotations
1415        Iterator iter = plot.getAnnotations().iterator();
1416        while (iter.hasNext()) {
1417            XYAnnotation a = (XYAnnotation) iter.next();
1418            applyToXYAnnotation(a);
1419        }
1420
1421        if (plot instanceof CombinedDomainXYPlot) {
1422            CombinedDomainXYPlot cp = (CombinedDomainXYPlot) plot;
1423            Iterator iterator = cp.getSubplots().iterator();
1424            while (iterator.hasNext()) {
1425                XYPlot subplot = (XYPlot) iterator.next();
1426                if (subplot != null) {
1427                    applyToPlot(subplot);
1428                }
1429            }
1430        }
1431        if (plot instanceof CombinedRangeXYPlot) {
1432            CombinedRangeXYPlot cp = (CombinedRangeXYPlot) plot;
1433            Iterator iterator = cp.getSubplots().iterator();
1434            while (iterator.hasNext()) {
1435                XYPlot subplot = (XYPlot) iterator.next();
1436                if (subplot != null) {
1437                    applyToPlot(subplot);
1438                }
1439            }
1440        }
1441    }
1442
1443    /**
1444     * Applies the attributes of this theme to a {@link FastScatterPlot}.
1445     * @param plot
1446     */
1447    protected void applyToFastScatterPlot(FastScatterPlot plot) {
1448        plot.setDomainGridlinePaint(this.domainGridlinePaint);
1449        plot.setRangeGridlinePaint(this.rangeGridlinePaint);
1450        ValueAxis xAxis = plot.getDomainAxis();
1451        if (xAxis != null) {
1452            applyToValueAxis(xAxis);
1453        }
1454        ValueAxis yAxis = plot.getRangeAxis();
1455        if (yAxis != null) {
1456            applyToValueAxis(yAxis);
1457        }
1458
1459    }
1460
1461    /**
1462     * Applies the attributes of this theme to a {@link PolarPlot}.  This
1463     * method is called from the {@link #applyToPlot(Plot)} method.
1464     *
1465     * @param plot  the plot (<code>null</code> not permitted).
1466     */
1467    protected void applyToPolarPlot(PolarPlot plot) {
1468        plot.setAngleLabelFont(this.regularFont);
1469        plot.setAngleLabelPaint(this.tickLabelPaint);
1470        plot.setAngleGridlinePaint(this.domainGridlinePaint);
1471        plot.setRadiusGridlinePaint(this.rangeGridlinePaint);
1472        ValueAxis axis = plot.getAxis();
1473        if (axis != null) {
1474            applyToValueAxis(axis);
1475        }
1476    }
1477
1478    /**
1479     * Applies the attributes of this theme to a {@link SpiderWebPlot}.
1480     *
1481     * @param plot  the plot (<code>null</code> not permitted).
1482     */
1483    protected void applyToSpiderWebPlot(SpiderWebPlot plot) {
1484        plot.setLabelFont(this.regularFont);
1485        plot.setLabelPaint(this.axisLabelPaint);
1486        plot.setAxisLinePaint(this.axisLabelPaint);
1487    }
1488
1489    /**
1490     * Applies the attributes of this theme to a {@link MeterPlot}.
1491     *
1492     * @param plot  the plot (<code>null</code> not permitted).
1493     */
1494    protected void applyToMeterPlot(MeterPlot plot) {
1495        plot.setDialBackgroundPaint(this.plotBackgroundPaint);
1496        plot.setValueFont(this.largeFont);
1497        plot.setValuePaint(this.axisLabelPaint);
1498        plot.setDialOutlinePaint(this.plotOutlinePaint);
1499        plot.setNeedlePaint(this.thermometerPaint);
1500        plot.setTickLabelFont(this.regularFont);
1501        plot.setTickLabelPaint(this.tickLabelPaint);
1502    }
1503
1504    /**
1505     * Applies the attributes for this theme to a {@link ThermometerPlot}.
1506     * This method is called from the {@link #applyToPlot(Plot)} method.
1507     *
1508     * @param plot  the plot.
1509     */
1510    protected void applyToThermometerPlot(ThermometerPlot plot) {
1511        plot.setValueFont(this.largeFont);
1512        plot.setThermometerPaint(this.thermometerPaint);
1513        ValueAxis axis = plot.getRangeAxis();
1514        if (axis != null) {
1515            applyToValueAxis(axis);
1516        }
1517    }
1518
1519    /**
1520     * Applies the attributes for this theme to a {@link CategoryAxis}.
1521     *
1522     * @param axis  the axis (<code>null</code> not permitted).
1523     */
1524    protected void applyToCategoryAxis(CategoryAxis axis) {
1525        axis.setLabelFont(this.largeFont);
1526        axis.setLabelPaint(this.axisLabelPaint);
1527        axis.setTickLabelFont(this.regularFont);
1528        axis.setTickLabelPaint(this.tickLabelPaint);
1529        if (axis instanceof SubCategoryAxis) {
1530            SubCategoryAxis sca = (SubCategoryAxis) axis;
1531            sca.setSubLabelFont(this.regularFont);
1532            sca.setSubLabelPaint(this.tickLabelPaint);
1533        }
1534    }
1535
1536    /**
1537     * Applies the attributes for this theme to a {@link ValueAxis}.
1538     *
1539     * @param axis  the axis (<code>null</code> not permitted).
1540     */
1541    protected void applyToValueAxis(ValueAxis axis) {
1542        axis.setLabelFont(this.largeFont);
1543        axis.setLabelPaint(this.axisLabelPaint);
1544        axis.setTickLabelFont(this.regularFont);
1545        axis.setTickLabelPaint(this.tickLabelPaint);
1546        if (axis instanceof SymbolAxis) {
1547            applyToSymbolAxis((SymbolAxis) axis);
1548        }
1549        if (axis instanceof PeriodAxis) {
1550            applyToPeriodAxis((PeriodAxis) axis);
1551        }
1552    }
1553
1554    /**
1555     * Applies the attributes for this theme to a {@link SymbolAxis}.
1556     *
1557     * @param axis  the axis (<code>null</code> not permitted).
1558     */
1559    protected void applyToSymbolAxis(SymbolAxis axis) {
1560        axis.setGridBandPaint(this.gridBandPaint);
1561        axis.setGridBandAlternatePaint(this.gridBandAlternatePaint);
1562    }
1563
1564    /**
1565     * Applies the attributes for this theme to a {@link PeriodAxis}.
1566     *
1567     * @param axis  the axis (<code>null</code> not permitted).
1568     */
1569    protected void applyToPeriodAxis(PeriodAxis axis) {
1570        PeriodAxisLabelInfo[] info = axis.getLabelInfo();
1571        for (int i = 0; i < info.length; i++) {
1572            PeriodAxisLabelInfo e = info[i];
1573            PeriodAxisLabelInfo n = new PeriodAxisLabelInfo(e.getPeriodClass(),
1574                    e.getDateFormat(), e.getPadding(), this.regularFont,
1575                    this.tickLabelPaint, e.getDrawDividers(),
1576                    e.getDividerStroke(), e.getDividerPaint());
1577            info[i] = n;
1578        }
1579        axis.setLabelInfo(info);
1580    }
1581
1582    /**
1583     * Applies the attributes for this theme to an {@link AbstractRenderer}.
1584     *
1585     * @param renderer  the renderer (<code>null</code> not permitted).
1586     */
1587    protected void applyToAbstractRenderer(AbstractRenderer renderer) {
1588        if (renderer.getAutoPopulateSeriesPaint()) {
1589            renderer.clearSeriesPaints(false);
1590        }
1591        if (renderer.getAutoPopulateSeriesStroke()) {
1592            renderer.clearSeriesStrokes(false);
1593        }
1594    }
1595
1596    /**
1597     * Applies the settings of this theme to the specified renderer.
1598     *
1599     * @param renderer  the renderer (<code>null</code> not permitted).
1600     */
1601    protected void applyToCategoryItemRenderer(CategoryItemRenderer renderer) {
1602        if (renderer == null) {
1603            throw new IllegalArgumentException("Null 'renderer' argument.");
1604        }
1605
1606        if (renderer instanceof AbstractRenderer) {
1607            applyToAbstractRenderer((AbstractRenderer) renderer);
1608        }
1609
1610        renderer.setBaseItemLabelFont(this.regularFont);
1611        renderer.setBaseItemLabelPaint(this.itemLabelPaint);
1612
1613        // now we handle some special cases - yes, UGLY code alert!
1614
1615        // BarRenderer
1616        if (renderer instanceof BarRenderer) {
1617            BarRenderer br = (BarRenderer) renderer;
1618            br.setBarPainter(this.barPainter);
1619            br.setShadowVisible(this.shadowVisible);
1620            br.setShadowPaint(this.shadowPaint);
1621        }
1622
1623        // BarRenderer3D
1624        if (renderer instanceof BarRenderer3D) {
1625            BarRenderer3D br3d = (BarRenderer3D) renderer;
1626            br3d.setWallPaint(this.wallPaint);
1627        }
1628
1629        // LineRenderer3D
1630        if (renderer instanceof LineRenderer3D) {
1631            LineRenderer3D lr3d = (LineRenderer3D) renderer;
1632            lr3d.setWallPaint(this.wallPaint);
1633        }
1634
1635        //  StatisticalBarRenderer
1636        if (renderer instanceof StatisticalBarRenderer) {
1637            StatisticalBarRenderer sbr = (StatisticalBarRenderer) renderer;
1638            sbr.setErrorIndicatorPaint(this.errorIndicatorPaint);
1639        }
1640
1641        // MinMaxCategoryRenderer
1642        if (renderer instanceof MinMaxCategoryRenderer) {
1643            MinMaxCategoryRenderer mmcr = (MinMaxCategoryRenderer) renderer;
1644            mmcr.setGroupPaint(this.errorIndicatorPaint);
1645        }
1646    }
1647
1648    /**
1649     * Applies the settings of this theme to the specified renderer.
1650     *
1651     * @param renderer  the renderer (<code>null</code> not permitted).
1652     */
1653    protected void applyToXYItemRenderer(XYItemRenderer renderer) {
1654        if (renderer == null) {
1655            throw new IllegalArgumentException("Null 'renderer' argument.");
1656        }
1657        if (renderer instanceof AbstractRenderer) {
1658            applyToAbstractRenderer((AbstractRenderer) renderer);
1659        }
1660        renderer.setBaseItemLabelFont(this.regularFont);
1661        renderer.setBaseItemLabelPaint(this.itemLabelPaint);
1662        if (renderer instanceof XYBarRenderer) {
1663            XYBarRenderer br = (XYBarRenderer) renderer;
1664            br.setBarPainter(this.xyBarPainter);
1665            br.setShadowVisible(this.shadowVisible);
1666        }
1667    }
1668
1669    /**
1670     * Applies the settings of this theme to the specified annotation.
1671     *
1672     * @param annotation  the annotation.
1673     */
1674    protected void applyToXYAnnotation(XYAnnotation annotation) {
1675        if (annotation == null) {
1676            throw new IllegalArgumentException("Null 'annotation' argument.");
1677        }
1678        if (annotation instanceof XYTextAnnotation) {
1679            XYTextAnnotation xyta = (XYTextAnnotation) annotation;
1680            xyta.setFont(this.smallFont);
1681            xyta.setPaint(this.itemLabelPaint);
1682        }
1683    }
1684
1685    /**
1686     * Tests this theme for equality with an arbitrary object.
1687     *
1688     * @param obj  the object (<code>null</code> permitted).
1689     *
1690     * @return A boolean.
1691     */
1692    public boolean equals(Object obj) {
1693        if (obj == this) {
1694            return true;
1695        }
1696        if (!(obj instanceof StandardChartTheme)) {
1697            return false;
1698        }
1699        StandardChartTheme that = (StandardChartTheme) obj;
1700        if (!this.name.equals(that.name)) {
1701            return false;
1702        }
1703        if (!this.extraLargeFont.equals(that.extraLargeFont)) {
1704            return false;
1705        }
1706        if (!this.largeFont.equals(that.largeFont)) {
1707            return false;
1708        }
1709        if (!this.regularFont.equals(that.regularFont)) {
1710            return false;
1711        }
1712        if (!this.smallFont.equals(that.smallFont)) {
1713            return false;
1714        }
1715        if (!PaintUtilities.equal(this.titlePaint, that.titlePaint)) {
1716            return false;
1717        }
1718        if (!PaintUtilities.equal(this.subtitlePaint, that.subtitlePaint)) {
1719            return false;
1720        }
1721        if (!PaintUtilities.equal(this.chartBackgroundPaint,
1722                that.chartBackgroundPaint)) {
1723            return false;
1724        }
1725        if (!PaintUtilities.equal(this.legendBackgroundPaint,
1726                that.legendBackgroundPaint)) {
1727            return false;
1728        }
1729        if (!PaintUtilities.equal(this.legendItemPaint, that.legendItemPaint)) {
1730            return false;
1731        }
1732        if (!this.drawingSupplier.equals(that.drawingSupplier)) {
1733            return false;
1734        }
1735        if (!PaintUtilities.equal(this.plotBackgroundPaint,
1736                that.plotBackgroundPaint)) {
1737            return false;
1738        }
1739        if (!PaintUtilities.equal(this.plotOutlinePaint,
1740                that.plotOutlinePaint)) {
1741            return false;
1742        }
1743        if (!this.labelLinkStyle.equals(that.labelLinkStyle)) {
1744            return false;
1745        }
1746        if (!PaintUtilities.equal(this.labelLinkPaint, that.labelLinkPaint)) {
1747            return false;
1748        }
1749        if (!PaintUtilities.equal(this.domainGridlinePaint,
1750                that.domainGridlinePaint)) {
1751            return false;
1752        }
1753        if (!PaintUtilities.equal(this.rangeGridlinePaint,
1754                that.rangeGridlinePaint)) {
1755            return false;
1756        }
1757        if (!PaintUtilities.equal(this.crosshairPaint, that.crosshairPaint)) {
1758            return false;
1759        }
1760        if (!this.axisOffset.equals(that.axisOffset)) {
1761            return false;
1762        }
1763        if (!PaintUtilities.equal(this.axisLabelPaint, that.axisLabelPaint)) {
1764            return false;
1765        }
1766        if (!PaintUtilities.equal(this.tickLabelPaint, that.tickLabelPaint)) {
1767            return false;
1768        }
1769        if (!PaintUtilities.equal(this.itemLabelPaint, that.itemLabelPaint)) {
1770            return false;
1771        }
1772        if (this.shadowVisible != that.shadowVisible) {
1773            return false;
1774        }
1775        if (!PaintUtilities.equal(this.shadowPaint, that.shadowPaint)) {
1776            return false;
1777        }
1778        if (!this.barPainter.equals(that.barPainter)) {
1779            return false;
1780        }
1781        if (!this.xyBarPainter.equals(that.xyBarPainter)) {
1782            return false;
1783        }
1784        if (!PaintUtilities.equal(this.thermometerPaint,
1785                that.thermometerPaint)) {
1786            return false;
1787        }
1788        if (!PaintUtilities.equal(this.wallPaint, that.wallPaint)) {
1789            return false;
1790        }
1791        if (!PaintUtilities.equal(this.errorIndicatorPaint,
1792                that.errorIndicatorPaint)) {
1793            return false;
1794        }
1795        if (!PaintUtilities.equal(this.gridBandPaint, that.gridBandPaint)) {
1796            return false;
1797        }
1798        if (!PaintUtilities.equal(this.gridBandAlternatePaint,
1799                that.gridBandAlternatePaint)) {
1800            return false;
1801        }
1802        return true;
1803    }
1804
1805    /**
1806     * Returns a clone of this theme.
1807     *
1808     * @return A clone.
1809     *
1810     * @throws CloneNotSupportedException if the theme cannot be cloned.
1811     */
1812    public Object clone() throws CloneNotSupportedException {
1813        return super.clone();
1814    }
1815
1816    /**
1817     * Provides serialization support.
1818     *
1819     * @param stream  the output stream (<code>null</code> not permitted).
1820     *
1821     * @throws IOException  if there is an I/O error.
1822     */
1823    private void writeObject(ObjectOutputStream stream) throws IOException {
1824        stream.defaultWriteObject();
1825        SerialUtilities.writePaint(this.titlePaint, stream);
1826        SerialUtilities.writePaint(this.subtitlePaint, stream);
1827        SerialUtilities.writePaint(this.chartBackgroundPaint, stream);
1828        SerialUtilities.writePaint(this.legendBackgroundPaint, stream);
1829        SerialUtilities.writePaint(this.legendItemPaint, stream);
1830        SerialUtilities.writePaint(this.plotBackgroundPaint, stream);
1831        SerialUtilities.writePaint(this.plotOutlinePaint, stream);
1832        SerialUtilities.writePaint(this.labelLinkPaint, stream);
1833        SerialUtilities.writePaint(this.baselinePaint, stream);
1834        SerialUtilities.writePaint(this.domainGridlinePaint, stream);
1835        SerialUtilities.writePaint(this.rangeGridlinePaint, stream);
1836        SerialUtilities.writePaint(this.crosshairPaint, stream);
1837        SerialUtilities.writePaint(this.axisLabelPaint, stream);
1838        SerialUtilities.writePaint(this.tickLabelPaint, stream);
1839        SerialUtilities.writePaint(this.itemLabelPaint, stream);
1840        SerialUtilities.writePaint(this.shadowPaint, stream);
1841        SerialUtilities.writePaint(this.thermometerPaint, stream);
1842        SerialUtilities.writePaint(this.wallPaint, stream);
1843        SerialUtilities.writePaint(this.errorIndicatorPaint, stream);
1844        SerialUtilities.writePaint(this.gridBandPaint, stream);
1845        SerialUtilities.writePaint(this.gridBandAlternatePaint, stream);
1846    }
1847
1848    /**
1849     * Provides serialization support.
1850     *
1851     * @param stream  the input stream (<code>null</code> not permitted).
1852     *
1853     * @throws IOException  if there is an I/O error.
1854     * @throws ClassNotFoundException  if there is a classpath problem.
1855     */
1856    private void readObject(ObjectInputStream stream)
1857        throws IOException, ClassNotFoundException {
1858        stream.defaultReadObject();
1859        this.titlePaint = SerialUtilities.readPaint(stream);
1860        this.subtitlePaint = SerialUtilities.readPaint(stream);
1861        this.chartBackgroundPaint = SerialUtilities.readPaint(stream);
1862        this.legendBackgroundPaint = SerialUtilities.readPaint(stream);
1863        this.legendItemPaint = SerialUtilities.readPaint(stream);
1864        this.plotBackgroundPaint = SerialUtilities.readPaint(stream);
1865        this.plotOutlinePaint = SerialUtilities.readPaint(stream);
1866        this.labelLinkPaint = SerialUtilities.readPaint(stream);
1867        this.baselinePaint = SerialUtilities.readPaint(stream);
1868        this.domainGridlinePaint = SerialUtilities.readPaint(stream);
1869        this.rangeGridlinePaint = SerialUtilities.readPaint(stream);
1870        this.crosshairPaint = SerialUtilities.readPaint(stream);
1871        this.axisLabelPaint = SerialUtilities.readPaint(stream);
1872        this.tickLabelPaint = SerialUtilities.readPaint(stream);
1873        this.itemLabelPaint = SerialUtilities.readPaint(stream);
1874        this.shadowPaint = SerialUtilities.readPaint(stream);
1875        this.thermometerPaint = SerialUtilities.readPaint(stream);
1876        this.wallPaint = SerialUtilities.readPaint(stream);
1877        this.errorIndicatorPaint = SerialUtilities.readPaint(stream);
1878        this.gridBandPaint = SerialUtilities.readPaint(stream);
1879        this.gridBandAlternatePaint = SerialUtilities.readPaint(stream);
1880    }
1881
1882}