001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2021, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * ------------------- 028 * CompositeTitle.java 029 * ------------------- 030 * (C) Copyright 2005-2021, by David Gilbert and Contributors. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 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; 046 047import org.jfree.chart.block.BlockContainer; 048import org.jfree.chart.block.BorderArrangement; 049import org.jfree.chart.block.RectangleConstraint; 050import org.jfree.chart.event.TitleChangeEvent; 051import org.jfree.chart.ui.Size2D; 052import org.jfree.chart.util.PaintUtils; 053import org.jfree.chart.util.Args; 054import org.jfree.chart.util.SerialUtils; 055 056/** 057 * A title that contains multiple titles within a {@link BlockContainer}. 058 */ 059public class CompositeTitle extends Title implements Cloneable, Serializable { 060 061 /** For serialization. */ 062 private static final long serialVersionUID = -6770854036232562290L; 063 064 /** 065 * The background paint. 066 */ 067 private transient Paint backgroundPaint; 068 069 /** A container for the individual titles. */ 070 private BlockContainer container; 071 072 /** 073 * Creates a new composite title with a default border arrangement. 074 */ 075 public CompositeTitle() { 076 this(new BlockContainer(new BorderArrangement())); 077 } 078 079 /** 080 * Creates a new title using the specified container. 081 * 082 * @param container the container ({@code null} not permitted). 083 */ 084 public CompositeTitle(BlockContainer container) { 085 Args.nullNotPermitted(container, "container"); 086 this.container = container; 087 this.backgroundPaint = null; 088 } 089 090 /** 091 * Returns the background paint. 092 * 093 * @return The paint (possibly {@code null}). 094 */ 095 public Paint getBackgroundPaint() { 096 return this.backgroundPaint; 097 } 098 099 /** 100 * Sets the background paint and sends a {@link TitleChangeEvent} to all 101 * registered listeners. If you set this attribute to {@code null}, 102 * no background is painted (which makes the title background transparent). 103 * 104 * @param paint the background paint ({@code null} permitted). 105 */ 106 public void setBackgroundPaint(Paint paint) { 107 this.backgroundPaint = paint; 108 notifyListeners(new TitleChangeEvent(this)); 109 } 110 111 /** 112 * Returns the container holding the titles. 113 * 114 * @return The title container (never {@code null}). 115 */ 116 public BlockContainer getContainer() { 117 return this.container; 118 } 119 120 /** 121 * Sets the title container. 122 * 123 * @param container the container ({@code null} not permitted). 124 */ 125 public void setTitleContainer(BlockContainer container) { 126 Args.nullNotPermitted(container, "container"); 127 this.container = container; 128 } 129 130 /** 131 * Arranges the contents of the block, within the given constraints, and 132 * returns the block size. 133 * 134 * @param g2 the graphics device. 135 * @param constraint the constraint ({@code null} not permitted). 136 * 137 * @return The block size (in Java2D units, never {@code null}). 138 */ 139 @Override 140 public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) { 141 RectangleConstraint contentConstraint = toContentConstraint(constraint); 142 Size2D contentSize = this.container.arrange(g2, contentConstraint); 143 return new Size2D(calculateTotalWidth(contentSize.getWidth()), 144 calculateTotalHeight(contentSize.getHeight())); 145 } 146 147 /** 148 * Draws the title on a Java 2D graphics device (such as the screen or a 149 * printer). 150 * 151 * @param g2 the graphics device. 152 * @param area the area allocated for the title. 153 */ 154 @Override 155 public void draw(Graphics2D g2, Rectangle2D area) { 156 draw(g2, area, null); 157 } 158 159 /** 160 * Draws the block within the specified area. 161 * 162 * @param g2 the graphics device. 163 * @param area the area. 164 * @param params ignored ({@code null} permitted). 165 * 166 * @return Always {@code null}. 167 */ 168 @Override 169 public Object draw(Graphics2D g2, Rectangle2D area, Object params) { 170 area = trimMargin(area); 171 drawBorder(g2, area); 172 area = trimBorder(area); 173 if (this.backgroundPaint != null) { 174 g2.setPaint(this.backgroundPaint); 175 g2.fill(area); 176 } 177 area = trimPadding(area); 178 return this.container.draw(g2, area, params); 179 } 180 181 /** 182 * Tests this title for equality with an arbitrary object. 183 * 184 * @param obj the object ({@code null} permitted). 185 * 186 * @return A boolean. 187 */ 188 @Override 189 public boolean equals(Object obj) { 190 if (obj == this) { 191 return true; 192 } 193 if (!(obj instanceof CompositeTitle)) { 194 return false; 195 } 196 CompositeTitle that = (CompositeTitle) obj; 197 if (!this.container.equals(that.container)) { 198 return false; 199 } 200 if (!PaintUtils.equal(this.backgroundPaint, that.backgroundPaint)) { 201 return false; 202 } 203 return super.equals(obj); 204 } 205 206 /** 207 * Provides serialization support. 208 * 209 * @param stream the output stream. 210 * 211 * @throws IOException if there is an I/O error. 212 */ 213 private void writeObject(ObjectOutputStream stream) throws IOException { 214 stream.defaultWriteObject(); 215 SerialUtils.writePaint(this.backgroundPaint, stream); 216 } 217 218 /** 219 * Provides serialization support. 220 * 221 * @param stream the input stream. 222 * 223 * @throws IOException if there is an I/O error. 224 * @throws ClassNotFoundException if there is a classpath problem. 225 */ 226 private void readObject(ObjectInputStream stream) 227 throws IOException, ClassNotFoundException { 228 stream.defaultReadObject(); 229 this.backgroundPaint = SerialUtils.readPaint(stream); 230 } 231 232}