001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package org.jfree.chart.block;
020
021import java.awt.Color;
022import java.awt.Font;
023import java.awt.Graphics2D;
024import java.awt.Paint;
025import java.awt.Shape;
026import java.awt.geom.Rectangle2D;
027import java.io.IOException;
028import java.io.ObjectInputStream;
029import java.io.ObjectOutputStream;
030
031import org.jfree.chart.entity.ChartEntity;
032import org.jfree.chart.entity.StandardEntityCollection;
033import org.jfree.io.SerialUtilities;
034import org.jfree.text.TextBlock;
035import org.jfree.text.TextBlockAnchor;
036import org.jfree.text.TextUtilities;
037import org.jfree.ui.HorizontalAlignment;
038import org.jfree.ui.Size2D;
039import org.jfree.util.ObjectUtilities;
040import org.jfree.util.PaintUtilities;
041import org.jfree.util.PublicCloneable;
042
043/**
044 * A block containing a label.
045 */
046public class LabelBlock extends AbstractBlock 
047                                implements Block, PublicCloneable {
048    
049    /** For serialization. */
050    static final long serialVersionUID = 249626098864178017L;
051
052    /** 
053     * The text for the label - retained in case the label needs 
054     * regenerating (for example, to change the font). 
055     */
056    private String text;
057    
058    /** The label. */
059    private TextBlock label;
060    
061    /** The font. */
062    private Font font;
063    
064    /** The tool tip text (can be <code>null</code>). */
065    private String toolTipText;
066    
067    /** The URL text (can be <code>null</code>). */
068    private String urlText;
069    
070    /** The default color. */
071    public static final Paint DEFAULT_PAINT = Color.black;
072
073    /** The paint. */
074    private transient Paint paint;
075    
076    /**
077     * Creates a new label block.
078     * 
079     * @param label  the label (<code>null</code> not permitted).
080     */
081    public LabelBlock(String label) {
082        this(label, new Font("SansSerif", Font.PLAIN, 10), DEFAULT_PAINT);
083    }
084    
085    /**
086     * Creates a new label block.
087     * 
088     * @param text  the text for the label (<code>null</code> not permitted).
089     * @param font  the font (<code>null</code> not permitted).
090     */
091    public LabelBlock(String text, Font font) {        
092        this(text, font, DEFAULT_PAINT);
093    }
094    
095    /**
096     * Creates a new label block.
097     *
098     * @param text  the text for the label (<code>null</code> not permitted).
099     * @param font  the font (<code>null</code> not permitted).
100     * @param paint the paint (<code>null</code> not permitted).
101     */
102    public LabelBlock(String text, Font font, Paint paint) {  
103        this.text = text;
104        this.paint = paint; 
105        this.label = TextUtilities.createTextBlock(text, font, this.paint); 
106        this.label.setLineAlignment(HorizontalAlignment.LEFT);
107        this.font = font;
108        this.toolTipText = null;
109        this.urlText = null;
110    }
111    
112    /**
113     * Returns the font.
114     * @return The font (never <code>null</code>).
115     */
116    public Font getFont() {
117        return this.font;    
118    }
119    
120    /**
121     * Sets the font and regenerates the label.
122     * @param font  the font (<code>null</code> not permitted).
123     */
124    public void setFont(Font font) {
125        if (font == null) {
126            throw new IllegalArgumentException("Null 'font' argument.");
127        }
128        this.font = font;
129        this.label = TextUtilities.createTextBlock(this.text, font, this.paint);
130        this.label.setLineAlignment(HorizontalAlignment.LEFT); 
131    }
132   
133    /**
134     * Returns the paint.
135     * @return The paint (never <code>null</code>).
136     */
137    public Paint getPaint() {
138        return this.paint;   
139    }
140   
141    /**
142     * Sets the paint and regenerates the label.
143     * @param paint  the paint (<code>null</code> not permitted).
144     */
145    public void setPaint(Paint paint) {
146        if (paint == null) {
147            throw new IllegalArgumentException("Null 'paint' argument.");
148        }
149        this.paint = paint;
150        this.label = TextUtilities.createTextBlock(this.text, this.font, this.paint);
151        this.label.setLineAlignment(HorizontalAlignment.LEFT); 
152    }
153
154    /**
155     * Returns the tool tip text.
156     * @return The tool tip text (possibly <code>null</code>).
157     */
158    public String getToolTipText() {
159        return this.toolTipText;
160    }
161    
162    /**
163     * Sets the tool tip text.
164     * @param text  the text (<code>null</code> permitted).
165     */
166    public void setToolTipText(String text) {
167        this.toolTipText = text;   
168    }
169    
170    /**
171     * Returns the URL text.
172     * @return The URL text (possibly <code>null</code>).
173     */
174    public String getURLText() {
175        return this.urlText;
176    }
177    
178    /**
179     * Sets the URL text.
180     * @param text  the text (<code>null</code> permitted).
181     */
182    public void setURLText(String text) {
183        this.urlText = text;   
184    }
185    
186    /**
187     * Arranges the contents of the block, within the given constraints, and 
188     * returns the block size.
189     * 
190     * @param g2  the graphics device.
191     * @param constraint  the constraint (<code>null</code> not permitted).
192     * 
193     * @return The block size (in Java2D units, never <code>null</code>).
194     */
195    public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) {
196        g2.setFont(this.font);
197        Size2D s = this.label.calculateDimensions(g2);
198        return new Size2D(calculateTotalWidth(s.getWidth()), 
199                calculateTotalHeight(s.getHeight()));
200    }
201    
202    /**
203     * Draws the block.
204     * 
205     * @param g2  the graphics device.
206     * @param area  the area.
207     */
208    public void draw(Graphics2D g2, Rectangle2D area) {
209        draw(g2, area, null);
210    }
211    
212    /**
213     * Draws the block within the specified area.
214     * 
215     * @param g2  the graphics device.
216     * @param area  the area.
217     * @param params  ignored (<code>null</code> permitted).
218     * 
219     * @return Always <code>null</code>.
220     */
221    public Object draw(Graphics2D g2, Rectangle2D area, Object params) {
222        area = trimMargin(area);
223        drawBorder(g2, area);
224        area = trimBorder(area);
225        area = trimPadding(area);
226        
227        // check if we need to collect chart entities from the container
228        EntityBlockParams ebp = null;
229        StandardEntityCollection sec = null;
230        Shape entityArea = null;
231        if (params instanceof EntityBlockParams) {
232            ebp = (EntityBlockParams) params;
233            if (ebp.getGenerateEntities()) {
234                sec = new StandardEntityCollection();
235                entityArea = (Shape) area.clone();
236            }
237        }
238        g2.setPaint(this.paint);
239        g2.setFont(this.font);
240        this.label.draw(g2, (float) area.getX(), (float) area.getY(), 
241                TextBlockAnchor.TOP_LEFT);
242        BlockResult result = null;
243        if (ebp != null && sec != null) {
244            if (this.toolTipText != null || this.urlText != null) {
245                ChartEntity entity = new ChartEntity(entityArea, 
246                        this.toolTipText, this.urlText);   
247                sec.add(entity);
248                result = new BlockResult();
249                result.setEntityCollection(sec);
250            }
251        }
252        return result;
253    }
254    
255    /**
256     * Tests this <code>LabelBlock</code> for equality with an arbitrary 
257     * object.
258     * 
259     * @param obj  the object (<code>null</code> permitted).
260     * 
261     * @return A boolean.
262     */
263    public boolean equals(Object obj) {
264        if (!(obj instanceof LabelBlock)) {
265            return false;
266        }
267        LabelBlock that = (LabelBlock) obj;
268        if (!this.text.equals(that.text)) {
269            return false;
270        }
271        if (!this.font.equals(that.font)) {
272            return false;
273        }
274        if (!PaintUtilities.equal(this.paint, that.paint)) {
275            return false;
276        }
277        if (!ObjectUtilities.equal(this.toolTipText, that.toolTipText)) {
278            return false;
279        }
280        if (!ObjectUtilities.equal(this.urlText, that.urlText)) {
281            return false;
282        }
283        return super.equals(obj);
284    }
285
286    /**
287     * Returns a clone of this <code>LabelBlock</code> instance.
288     * 
289     * @return A clone.
290     * 
291     * @throws CloneNotSupportedException if there is a problem cloning.
292     */
293    public Object clone() throws CloneNotSupportedException {
294        return super.clone();
295    }
296    
297    /**
298     * Provides serialization support.
299     *
300     * @param stream  the output stream.
301     *
302     * @throws IOException if there is an I/O error.
303     */
304    private void writeObject(ObjectOutputStream stream) throws IOException {
305        stream.defaultWriteObject();
306        SerialUtilities.writePaint(this.paint, stream);
307    }
308
309    /**
310     * Provides serialization support.
311     *
312     * @param stream  the input stream.
313     *
314     * @throws IOException  if there is an I/O error.
315     * @throws ClassNotFoundException  if there is a classpath problem.
316     */
317    private void readObject(ObjectInputStream stream) 
318        throws IOException, ClassNotFoundException {
319        stream.defaultReadObject();
320        this.paint = SerialUtilities.readPaint(stream);
321    }
322
323}