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