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 * CompositeTitle.java 029 * ------------------- 030 * (C) Copyright 2005-2021, by David Gilbert and Contributors. 031 * 032 * Original Author: David Gilbert; 033 * Contributor(s): Eric Penfold (patch 2006826); 034 * 035 */ 036 037package org.jfree.chart.title; 038 039import java.awt.Graphics2D; 040import java.awt.Paint; 041import java.awt.geom.Rectangle2D; 042import java.io.IOException; 043import java.io.ObjectInputStream; 044import java.io.ObjectOutputStream; 045import java.io.Serializable; 046import org.jfree.chart.ChartElementVisitor; 047 048import org.jfree.chart.block.BlockContainer; 049import org.jfree.chart.block.BorderArrangement; 050import org.jfree.chart.block.RectangleConstraint; 051import org.jfree.chart.event.TitleChangeEvent; 052import org.jfree.chart.block.Size2D; 053import org.jfree.chart.internal.PaintUtils; 054import org.jfree.chart.internal.Args; 055import org.jfree.chart.internal.SerialUtils; 056 057/** 058 * A title that contains multiple titles within a {@link BlockContainer}. 059 */ 060public class CompositeTitle extends Title implements Cloneable, Serializable { 061 062 /** For serialization. */ 063 private static final long serialVersionUID = -6770854036232562290L; 064 065 /** 066 * The background paint. 067 */ 068 private transient Paint backgroundPaint; 069 070 /** A container for the individual titles. */ 071 private BlockContainer container; 072 073 /** 074 * Creates a new composite title with a default border arrangement. 075 */ 076 public CompositeTitle() { 077 this(new BlockContainer(new BorderArrangement())); 078 } 079 080 /** 081 * Creates a new title using the specified container. 082 * 083 * @param container the container ({@code null} not permitted). 084 */ 085 public CompositeTitle(BlockContainer container) { 086 Args.nullNotPermitted(container, "container"); 087 this.container = container; 088 this.backgroundPaint = null; 089 } 090 091 /** 092 * Returns the background paint. 093 * 094 * @return The paint (possibly {@code null}). 095 */ 096 public Paint getBackgroundPaint() { 097 return this.backgroundPaint; 098 } 099 100 /** 101 * Sets the background paint and sends a {@link TitleChangeEvent} to all 102 * registered listeners. If you set this attribute to {@code null}, 103 * no background is painted (which makes the title background transparent). 104 * 105 * @param paint the background paint ({@code null} permitted). 106 */ 107 public void setBackgroundPaint(Paint paint) { 108 this.backgroundPaint = paint; 109 notifyListeners(new TitleChangeEvent(this)); 110 } 111 112 /** 113 * Returns the container holding the titles. 114 * 115 * @return The title container (never {@code null}). 116 */ 117 public BlockContainer getContainer() { 118 return this.container; 119 } 120 121 /** 122 * Sets the title container. 123 * 124 * @param container the container ({@code null} not permitted). 125 */ 126 public void setTitleContainer(BlockContainer container) { 127 Args.nullNotPermitted(container, "container"); 128 this.container = container; 129 } 130 131 /** 132 * Arranges the contents of the block, within the given constraints, and 133 * returns the block size. 134 * 135 * @param g2 the graphics device. 136 * @param constraint the constraint ({@code null} not permitted). 137 * 138 * @return The block size (in Java2D units, never {@code null}). 139 */ 140 @Override 141 public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) { 142 RectangleConstraint contentConstraint = toContentConstraint(constraint); 143 Size2D contentSize = this.container.arrange(g2, contentConstraint); 144 return new Size2D(calculateTotalWidth(contentSize.getWidth()), 145 calculateTotalHeight(contentSize.getHeight())); 146 } 147 148 /** 149 * Receives a chart element visitor. 150 * 151 * @param visitor the visitor ({@code null} not permitted). 152 */ 153 @Override 154 public void receive(ChartElementVisitor visitor) { 155 // FIXME : add handling for BlockContainer 156 visitor.visit(this); 157 } 158 159 /** 160 * Draws the title on a Java 2D graphics device (such as the screen or a 161 * printer). 162 * 163 * @param g2 the graphics device. 164 * @param area the area allocated for the title. 165 */ 166 @Override 167 public void draw(Graphics2D g2, Rectangle2D area) { 168 draw(g2, area, null); 169 } 170 171 /** 172 * Draws the block within the specified area. 173 * 174 * @param g2 the graphics device. 175 * @param area the area. 176 * @param params ignored ({@code null} permitted). 177 * 178 * @return Always {@code null}. 179 */ 180 @Override 181 public Object draw(Graphics2D g2, Rectangle2D area, Object params) { 182 area = trimMargin(area); 183 drawBorder(g2, area); 184 area = trimBorder(area); 185 if (this.backgroundPaint != null) { 186 g2.setPaint(this.backgroundPaint); 187 g2.fill(area); 188 } 189 area = trimPadding(area); 190 return this.container.draw(g2, area, params); 191 } 192 193 /** 194 * Tests this title for equality with an arbitrary object. 195 * 196 * @param obj the object ({@code null} permitted). 197 * 198 * @return A boolean. 199 */ 200 @Override 201 public boolean equals(Object obj) { 202 if (obj == this) { 203 return true; 204 } 205 if (!(obj instanceof CompositeTitle)) { 206 return false; 207 } 208 CompositeTitle that = (CompositeTitle) obj; 209 if (!this.container.equals(that.container)) { 210 return false; 211 } 212 if (!PaintUtils.equal(this.backgroundPaint, that.backgroundPaint)) { 213 return false; 214 } 215 return super.equals(obj); 216 } 217 218 /** 219 * Provides serialization support. 220 * 221 * @param stream the output stream. 222 * 223 * @throws IOException if there is an I/O error. 224 */ 225 private void writeObject(ObjectOutputStream stream) throws IOException { 226 stream.defaultWriteObject(); 227 SerialUtils.writePaint(this.backgroundPaint, stream); 228 } 229 230 /** 231 * Provides serialization support. 232 * 233 * @param stream the input stream. 234 * 235 * @throws IOException if there is an I/O error. 236 * @throws ClassNotFoundException if there is a classpath problem. 237 */ 238 private void readObject(ObjectInputStream stream) 239 throws IOException, ClassNotFoundException { 240 stream.defaultReadObject(); 241 this.backgroundPaint = SerialUtils.readPaint(stream); 242 } 243 244}