001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2009, 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-2009, 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 * 10-Feb-2009 : Added alignment fields (DG);
048 *
049 */
050
051package org.jfree.chart.block;
052
053import java.awt.Color;
054import java.awt.Font;
055import java.awt.Graphics2D;
056import java.awt.Paint;
057import java.awt.Shape;
058import java.awt.geom.Point2D;
059import java.awt.geom.Rectangle2D;
060import java.io.IOException;
061import java.io.ObjectInputStream;
062import java.io.ObjectOutputStream;
063
064import org.jfree.chart.entity.ChartEntity;
065import org.jfree.chart.entity.StandardEntityCollection;
066import org.jfree.io.SerialUtilities;
067import org.jfree.text.TextBlock;
068import org.jfree.text.TextBlockAnchor;
069import org.jfree.text.TextUtilities;
070import org.jfree.ui.RectangleAnchor;
071import org.jfree.ui.Size2D;
072import org.jfree.util.ObjectUtilities;
073import org.jfree.util.PaintUtilities;
074import org.jfree.util.PublicCloneable;
075
076/**
077 * A block containing a label.
078 */
079public class LabelBlock extends AbstractBlock
080        implements Block, PublicCloneable {
081
082    /** For serialization. */
083    static final long serialVersionUID = 249626098864178017L;
084
085    /**
086     * The text for the label - retained in case the label needs
087     * regenerating (for example, to change the font).
088     */
089    private String text;
090
091    /** The label. */
092    private TextBlock label;
093
094    /** The font. */
095    private Font font;
096
097    /** The tool tip text (can be <code>null</code>). */
098    private String toolTipText;
099
100    /** The URL text (can be <code>null</code>). */
101    private String urlText;
102
103    /** The default color. */
104    public static final Paint DEFAULT_PAINT = Color.black;
105
106    /** The paint. */
107    private transient Paint paint;
108
109    /**
110     * The content alignment point.
111     *
112     * @since 1.0.13
113     */
114    private TextBlockAnchor contentAlignmentPoint;
115
116    /**
117     * The anchor point for the text.
118     *
119     * @since 1.0.13
120     */
121    private RectangleAnchor textAnchor;
122
123    /**
124     * Creates a new label block.
125     *
126     * @param label  the label (<code>null</code> not permitted).
127     */
128    public LabelBlock(String label) {
129        this(label, new Font("SansSerif", Font.PLAIN, 10), DEFAULT_PAINT);
130    }
131
132    /**
133     * Creates a new label block.
134     *
135     * @param text  the text for the label (<code>null</code> not permitted).
136     * @param font  the font (<code>null</code> not permitted).
137     */
138    public LabelBlock(String text, Font font) {
139        this(text, font, DEFAULT_PAINT);
140    }
141
142    /**
143     * Creates a new label block.
144     *
145     * @param text  the text for the label (<code>null</code> not permitted).
146     * @param font  the font (<code>null</code> not permitted).
147     * @param paint the paint (<code>null</code> not permitted).
148     */
149    public LabelBlock(String text, Font font, Paint paint) {
150        this.text = text;
151        this.paint = paint;
152        this.label = TextUtilities.createTextBlock(text, font, this.paint);
153        this.font = font;
154        this.toolTipText = null;
155        this.urlText = null;
156        this.contentAlignmentPoint = TextBlockAnchor.CENTER;
157        this.textAnchor = RectangleAnchor.CENTER;
158    }
159
160    /**
161     * Returns the font.
162     *
163     * @return The font (never <code>null</code>).
164     *
165     * @see #setFont(Font)
166     */
167    public Font getFont() {
168        return this.font;
169    }
170
171    /**
172     * Sets the font and regenerates the label.
173     *
174     * @param font  the font (<code>null</code> not permitted).
175     *
176     * @see #getFont()
177     */
178    public void setFont(Font font) {
179        if (font == null) {
180            throw new IllegalArgumentException("Null 'font' argument.");
181        }
182        this.font = font;
183        this.label = TextUtilities.createTextBlock(this.text, font, this.paint);
184    }
185
186    /**
187     * Returns the paint.
188     *
189     * @return The paint (never <code>null</code>).
190     *
191     * @see #setPaint(Paint)
192     */
193    public Paint getPaint() {
194        return this.paint;
195    }
196
197    /**
198     * Sets the paint and regenerates the label.
199     *
200     * @param paint  the paint (<code>null</code> not permitted).
201     *
202     * @see #getPaint()
203     */
204    public void setPaint(Paint paint) {
205        if (paint == null) {
206            throw new IllegalArgumentException("Null 'paint' argument.");
207        }
208        this.paint = paint;
209        this.label = TextUtilities.createTextBlock(this.text, this.font,
210                this.paint);
211    }
212
213    /**
214     * Returns the tool tip text.
215     *
216     * @return The tool tip text (possibly <code>null</code>).
217     *
218     * @see #setToolTipText(String)
219     */
220    public String getToolTipText() {
221        return this.toolTipText;
222    }
223
224    /**
225     * Sets the tool tip text.
226     *
227     * @param text  the text (<code>null</code> permitted).
228     *
229     * @see #getToolTipText()
230     */
231    public void setToolTipText(String text) {
232        this.toolTipText = text;
233    }
234
235    /**
236     * Returns the URL text.
237     *
238     * @return The URL text (possibly <code>null</code>).
239     *
240     * @see #setURLText(String)
241     */
242    public String getURLText() {
243        return this.urlText;
244    }
245
246    /**
247     * Sets the URL text.
248     *
249     * @param text  the text (<code>null</code> permitted).
250     *
251     * @see #getURLText()
252     */
253    public void setURLText(String text) {
254        this.urlText = text;
255    }
256
257    /**
258     * Returns the content alignment point.
259     *
260     * @return The content alignment point (never <code>null</code>).
261     *
262     * @since 1.0.13
263     */
264    public TextBlockAnchor getContentAlignmentPoint() {
265        return this.contentAlignmentPoint;
266    }
267
268    /**
269     * Sets the content alignment point.
270     *
271     * @param anchor  the anchor used to determine the alignment point (never
272     *         <code>null</code>).
273     *
274     * @since 1.0.13
275     */
276    public void setContentAlignmentPoint(TextBlockAnchor anchor) {
277        if (anchor == null) {
278            throw new IllegalArgumentException("Null 'anchor' argument.");
279        }
280        this.contentAlignmentPoint = anchor;
281    }
282
283    /**
284     * Returns the text anchor (never <code>null</code>).
285     *
286     * @return The text anchor.
287     *
288     * @since 1.0.13
289     */
290    public RectangleAnchor getTextAnchor() {
291        return this.textAnchor;
292    }
293
294    /**
295     * Sets the text anchor.
296     *
297     * @param anchor  the anchor (<code>null</code> not permitted).
298     *
299     * @since 1.0.13
300     */
301    public void setTextAnchor(RectangleAnchor anchor) {
302        this.textAnchor = anchor;
303    }
304
305    /**
306     * Arranges the contents of the block, within the given constraints, and
307     * returns the block size.
308     *
309     * @param g2  the graphics device.
310     * @param constraint  the constraint (<code>null</code> not permitted).
311     *
312     * @return The block size (in Java2D units, never <code>null</code>).
313     */
314    public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) {
315        g2.setFont(this.font);
316        Size2D s = this.label.calculateDimensions(g2);
317        return new Size2D(calculateTotalWidth(s.getWidth()),
318                calculateTotalHeight(s.getHeight()));
319    }
320
321    /**
322     * Draws the block.
323     *
324     * @param g2  the graphics device.
325     * @param area  the area.
326     */
327    public void draw(Graphics2D g2, Rectangle2D area) {
328        draw(g2, area, null);
329    }
330
331    /**
332     * Draws the block within the specified area.
333     *
334     * @param g2  the graphics device.
335     * @param area  the area.
336     * @param params  ignored (<code>null</code> permitted).
337     *
338     * @return Always <code>null</code>.
339     */
340    public Object draw(Graphics2D g2, Rectangle2D area, Object params) {
341        area = trimMargin(area);
342        drawBorder(g2, area);
343        area = trimBorder(area);
344        area = trimPadding(area);
345
346        // check if we need to collect chart entities from the container
347        EntityBlockParams ebp = null;
348        StandardEntityCollection sec = null;
349        Shape entityArea = null;
350        if (params instanceof EntityBlockParams) {
351            ebp = (EntityBlockParams) params;
352            if (ebp.getGenerateEntities()) {
353                sec = new StandardEntityCollection();
354                entityArea = (Shape) area.clone();
355            }
356        }
357        g2.setPaint(this.paint);
358        g2.setFont(this.font);
359        Point2D pt = RectangleAnchor.coordinates(area, this.textAnchor);
360        this.label.draw(g2, (float) pt.getX(), (float) pt.getY(),
361                this.contentAlignmentPoint);
362        BlockResult result = null;
363        if (ebp != null && sec != null) {
364            if (this.toolTipText != null || this.urlText != null) {
365                ChartEntity entity = new ChartEntity(entityArea,
366                        this.toolTipText, this.urlText);
367                sec.add(entity);
368                result = new BlockResult();
369                result.setEntityCollection(sec);
370            }
371        }
372        return result;
373    }
374
375    /**
376     * Tests this <code>LabelBlock</code> for equality with an arbitrary
377     * object.
378     *
379     * @param obj  the object (<code>null</code> permitted).
380     *
381     * @return A boolean.
382     */
383    public boolean equals(Object obj) {
384        if (!(obj instanceof LabelBlock)) {
385            return false;
386        }
387        LabelBlock that = (LabelBlock) obj;
388        if (!this.text.equals(that.text)) {
389            return false;
390        }
391        if (!this.font.equals(that.font)) {
392            return false;
393        }
394        if (!PaintUtilities.equal(this.paint, that.paint)) {
395            return false;
396        }
397        if (!ObjectUtilities.equal(this.toolTipText, that.toolTipText)) {
398            return false;
399        }
400        if (!ObjectUtilities.equal(this.urlText, that.urlText)) {
401            return false;
402        }
403        if (!this.contentAlignmentPoint.equals(that.contentAlignmentPoint)) {
404            return false;
405        }
406        if (!this.textAnchor.equals(that.textAnchor)) {
407            return false;
408        }
409        return super.equals(obj);
410    }
411
412    /**
413     * Returns a clone of this <code>LabelBlock</code> instance.
414     *
415     * @return A clone.
416     *
417     * @throws CloneNotSupportedException if there is a problem cloning.
418     */
419    public Object clone() throws CloneNotSupportedException {
420        return super.clone();
421    }
422
423    /**
424     * Provides serialization support.
425     *
426     * @param stream  the output stream.
427     *
428     * @throws IOException if there is an I/O error.
429     */
430    private void writeObject(ObjectOutputStream stream) throws IOException {
431        stream.defaultWriteObject();
432        SerialUtilities.writePaint(this.paint, stream);
433    }
434
435    /**
436     * Provides serialization support.
437     *
438     * @param stream  the input stream.
439     *
440     * @throws IOException  if there is an I/O error.
441     * @throws ClassNotFoundException  if there is a classpath problem.
442     */
443    private void readObject(ObjectInputStream stream)
444        throws IOException, ClassNotFoundException {
445        stream.defaultReadObject();
446        this.paint = SerialUtilities.readPaint(stream);
447    }
448
449}