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    
051    package org.jfree.chart.block;
052    
053    import java.awt.Color;
054    import java.awt.Font;
055    import java.awt.Graphics2D;
056    import java.awt.Paint;
057    import java.awt.Shape;
058    import java.awt.geom.Point2D;
059    import java.awt.geom.Rectangle2D;
060    import java.io.IOException;
061    import java.io.ObjectInputStream;
062    import java.io.ObjectOutputStream;
063    
064    import org.jfree.chart.entity.ChartEntity;
065    import org.jfree.chart.entity.StandardEntityCollection;
066    import org.jfree.io.SerialUtilities;
067    import org.jfree.text.TextBlock;
068    import org.jfree.text.TextBlockAnchor;
069    import org.jfree.text.TextUtilities;
070    import org.jfree.ui.RectangleAnchor;
071    import org.jfree.ui.Size2D;
072    import org.jfree.util.ObjectUtilities;
073    import org.jfree.util.PaintUtilities;
074    import org.jfree.util.PublicCloneable;
075    
076    /**
077     * A block containing a label.
078     */
079    public 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    }