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