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