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