001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, 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 * LabelBlock.java
029 * ---------------
030 * (C) Copyright 2004-2007, by Object Refinery Limited.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   Pierre-Marie Le Biot;
034 *
035 * Changes:
036 * --------
037 * 22-Oct-2004 : Version 1 (DG);
038 * 19-Apr-2005 : Added optional tooltip and URL text items,
039 *               draw() method now returns entities if 
040 *               requested (DG);
041 * 13-May-2005 : Added methods to set the font (DG);
042 * 01-Sep-2005 : Added paint management (PMLB);
043 *               Implemented equals() and clone() (PublicCloneable) (DG);
044 * ------------- JFREECHART 1.0.x ---------------------------------------------
045 * 20-Jul-2006 : Fixed entity area in draw() method (DG);
046 * 16-Mar-2007 : Fixed serialization when using GradientPaint (DG);
047 * 
048 */
049
050package org.jfree.chart.block;
051
052import java.awt.Color;
053import java.awt.Font;
054import java.awt.Graphics2D;
055import java.awt.Paint;
056import java.awt.Shape;
057import java.awt.geom.Rectangle2D;
058import java.io.IOException;
059import java.io.ObjectInputStream;
060import java.io.ObjectOutputStream;
061
062import org.jfree.chart.entity.ChartEntity;
063import org.jfree.chart.entity.StandardEntityCollection;
064import org.jfree.io.SerialUtilities;
065import org.jfree.text.TextBlock;
066import org.jfree.text.TextBlockAnchor;
067import org.jfree.text.TextUtilities;
068import org.jfree.ui.Size2D;
069import org.jfree.util.ObjectUtilities;
070import org.jfree.util.PaintUtilities;
071import org.jfree.util.PublicCloneable;
072
073/**
074 * A block containing a label.
075 */
076public class LabelBlock extends AbstractBlock 
077                                implements Block, PublicCloneable {
078    
079    /** For serialization. */
080    static final long serialVersionUID = 249626098864178017L;
081
082    /** 
083     * The text for the label - retained in case the label needs 
084     * regenerating (for example, to change the font). 
085     */
086    private String text;
087    
088    /** The label. */
089    private TextBlock label;
090    
091    /** The font. */
092    private Font font;
093    
094    /** The tool tip text (can be <code>null</code>). */
095    private String toolTipText;
096    
097    /** The URL text (can be <code>null</code>). */
098    private String urlText;
099    
100    /** The default color. */
101    public static final Paint DEFAULT_PAINT = Color.black;
102
103    /** The paint. */
104    private transient Paint paint;
105    
106    /**
107     * Creates a new label block.
108     * 
109     * @param label  the label (<code>null</code> not permitted).
110     */
111    public LabelBlock(String label) {
112        this(label, new Font("SansSerif", Font.PLAIN, 10), DEFAULT_PAINT);
113    }
114    
115    /**
116     * Creates a new label block.
117     * 
118     * @param text  the text for the label (<code>null</code> not permitted).
119     * @param font  the font (<code>null</code> not permitted).
120     */
121    public LabelBlock(String text, Font font) {        
122        this(text, font, DEFAULT_PAINT);
123    }
124    
125    /**
126     * Creates a new label block.
127     *
128     * @param text  the text for the label (<code>null</code> not permitted).
129     * @param font  the font (<code>null</code> not permitted).
130     * @param paint the paint (<code>null</code> not permitted).
131     */
132    public LabelBlock(String text, Font font, Paint paint) {        
133        this.text = text;
134        this.paint = paint; 
135        this.label = TextUtilities.createTextBlock(text, font, this.paint); 
136        this.font = font;
137        this.toolTipText = null;
138        this.urlText = null;
139    }
140    
141    /**
142     * Returns the font.
143     *
144     * @return The font (never <code>null</code>).
145     * 
146     * @see #setFont(Font)
147     */
148    public Font getFont() {
149        return this.font;    
150    }
151    
152    /**
153     * Sets the font and regenerates the label.
154     *
155     * @param font  the font (<code>null</code> not permitted).
156     * 
157     * @see #getFont()
158     */
159    public void setFont(Font font) {
160        if (font == null) {
161            throw new IllegalArgumentException("Null 'font' argument.");
162        }
163        this.font = font;
164        this.label = TextUtilities.createTextBlock(this.text, font, this.paint);
165    }
166   
167    /**
168     * Returns the paint.
169     *
170     * @return The paint (never <code>null</code>).
171     * 
172     * @see #setPaint(Paint)
173     */
174    public Paint getPaint() {
175        return this.paint;   
176    }
177   
178    /**
179     * Sets the paint and regenerates the label.
180     *
181     * @param paint  the paint (<code>null</code> not permitted).
182     * 
183     * @see #getPaint()
184     */
185    public void setPaint(Paint paint) {
186        if (paint == null) {
187            throw new IllegalArgumentException("Null 'paint' argument.");
188        }
189        this.paint = paint;
190        this.label = TextUtilities.createTextBlock(this.text, this.font, 
191                this.paint);
192    }
193
194    /**
195     * Returns the tool tip text.
196     * 
197     * @return The tool tip text (possibly <code>null</code>).
198     * 
199     * @see #setToolTipText(String)
200     */
201    public String getToolTipText() {
202        return this.toolTipText;
203    }
204    
205    /**
206     * Sets the tool tip text.
207     * 
208     * @param text  the text (<code>null</code> permitted).
209     * 
210     * @see #getToolTipText()
211     */
212    public void setToolTipText(String text) {
213        this.toolTipText = text;   
214    }
215    
216    /**
217     * Returns the URL text.
218     * 
219     * @return The URL text (possibly <code>null</code>).
220     * 
221     * @see #setURLText(String)
222     */
223    public String getURLText() {
224        return this.urlText;
225    }
226    
227    /**
228     * Sets the URL text.
229     * 
230     * @param text  the text (<code>null</code> permitted).
231     * 
232     * @see #getURLText()
233     */
234    public void setURLText(String text) {
235        this.urlText = text;   
236    }
237    
238    /**
239     * Arranges the contents of the block, within the given constraints, and 
240     * returns the block size.
241     * 
242     * @param g2  the graphics device.
243     * @param constraint  the constraint (<code>null</code> not permitted).
244     * 
245     * @return The block size (in Java2D units, never <code>null</code>).
246     */
247    public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) {
248        g2.setFont(this.font);
249        Size2D s = this.label.calculateDimensions(g2);
250        return new Size2D(calculateTotalWidth(s.getWidth()), 
251                calculateTotalHeight(s.getHeight()));
252    }
253    
254    /**
255     * Draws the block.
256     * 
257     * @param g2  the graphics device.
258     * @param area  the area.
259     */
260    public void draw(Graphics2D g2, Rectangle2D area) {
261        draw(g2, area, null);
262    }
263    
264    /**
265     * Draws the block within the specified area.
266     * 
267     * @param g2  the graphics device.
268     * @param area  the area.
269     * @param params  ignored (<code>null</code> permitted).
270     * 
271     * @return Always <code>null</code>.
272     */
273    public Object draw(Graphics2D g2, Rectangle2D area, Object params) {
274        area = trimMargin(area);
275        drawBorder(g2, area);
276        area = trimBorder(area);
277        area = trimPadding(area);
278        
279        // check if we need to collect chart entities from the container
280        EntityBlockParams ebp = null;
281        StandardEntityCollection sec = null;
282        Shape entityArea = null;
283        if (params instanceof EntityBlockParams) {
284            ebp = (EntityBlockParams) params;
285            if (ebp.getGenerateEntities()) {
286                sec = new StandardEntityCollection();
287                entityArea = (Shape) area.clone();
288            }
289        }
290        g2.setPaint(this.paint);
291        g2.setFont(this.font);
292        this.label.draw(g2, (float) area.getX(), (float) area.getY(), 
293                TextBlockAnchor.TOP_LEFT);
294        BlockResult result = null;
295        if (ebp != null && sec != null) {
296            if (this.toolTipText != null || this.urlText != null) {
297                ChartEntity entity = new ChartEntity(entityArea, 
298                        this.toolTipText, this.urlText);   
299                sec.add(entity);
300                result = new BlockResult();
301                result.setEntityCollection(sec);
302            }
303        }
304        return result;
305    }
306    
307    /**
308     * Tests this <code>LabelBlock</code> for equality with an arbitrary 
309     * object.
310     * 
311     * @param obj  the object (<code>null</code> permitted).
312     * 
313     * @return A boolean.
314     */
315    public boolean equals(Object obj) {
316        if (!(obj instanceof LabelBlock)) {
317            return false;
318        }
319        LabelBlock that = (LabelBlock) obj;
320        if (!this.text.equals(that.text)) {
321            return false;
322        }
323        if (!this.font.equals(that.font)) {
324            return false;
325        }
326        if (!PaintUtilities.equal(this.paint, that.paint)) {
327            return false;
328        }
329        if (!ObjectUtilities.equal(this.toolTipText, that.toolTipText)) {
330            return false;
331        }
332        if (!ObjectUtilities.equal(this.urlText, that.urlText)) {
333            return false;
334        }
335        return super.equals(obj);
336    }
337
338    /**
339     * Returns a clone of this <code>LabelBlock</code> instance.
340     * 
341     * @return A clone.
342     * 
343     * @throws CloneNotSupportedException if there is a problem cloning.
344     */
345    public Object clone() throws CloneNotSupportedException {
346        return super.clone();
347    }
348    
349    /**
350     * Provides serialization support.
351     *
352     * @param stream  the output stream.
353     *
354     * @throws IOException if there is an I/O error.
355     */
356    private void writeObject(ObjectOutputStream stream) throws IOException {
357        stream.defaultWriteObject();
358        SerialUtilities.writePaint(this.paint, stream);
359    }
360
361    /**
362     * Provides serialization support.
363     *
364     * @param stream  the input stream.
365     *
366     * @throws IOException  if there is an I/O error.
367     * @throws ClassNotFoundException  if there is a classpath problem.
368     */
369    private void readObject(ObjectInputStream stream) 
370        throws IOException, ClassNotFoundException {
371        stream.defaultReadObject();
372        this.paint = SerialUtilities.readPaint(stream);
373    }
374
375}