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