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