001/* ========================================================================
002 * JCommon : a free general purpose class 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/jcommon/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 * TextBox.java
029 * ------------
030 * (C) Copyright 2004, by Object Refinery Limited and Contributors.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 * $Id: TextBox.java,v 1.12 2005/11/16 15:58:41 taqua Exp $
036 *
037 * Changes
038 * -------
039 * 09-Mar-2004 : Version 1 (DG);
040 * 22-Mar-2004 : Added equals() method and implemented Serializable (DG);
041 * 09-Nov-2004 : Renamed getAdjustedHeight() --> calculateExtendedHeight() in 
042 *               Spacer class (DG);
043 * 22-Feb-2005 : Replaced Spacer with RectangleInsets (DG);
044 *
045 */
046
047package org.jfree.text;
048
049import java.awt.BasicStroke;
050import java.awt.Color;
051import java.awt.Font;
052import java.awt.Graphics2D;
053import java.awt.Paint;
054import java.awt.Stroke;
055import java.awt.geom.Rectangle2D;
056import java.io.IOException;
057import java.io.ObjectInputStream;
058import java.io.ObjectOutputStream;
059import java.io.Serializable;
060
061import org.jfree.io.SerialUtilities;
062import org.jfree.ui.RectangleAnchor;
063import org.jfree.ui.RectangleInsets;
064import org.jfree.ui.Size2D;
065import org.jfree.util.ObjectUtilities;
066
067/**
068 * A box containing a text block.
069 *
070 * @author David Gilbert
071 */
072public class TextBox implements Serializable {
073    
074    /** For serialization. */
075    private static final long serialVersionUID = 3360220213180203706L;
076    
077    /** The outline paint. */
078    private transient Paint outlinePaint;
079    
080    /** The outline stroke. */
081    private transient Stroke outlineStroke;
082    
083    /** The interior space. */
084    private RectangleInsets interiorGap;
085    
086    /** The background paint. */
087    private transient Paint backgroundPaint;
088    
089    /** The shadow paint. */
090    private transient Paint shadowPaint;
091    
092    /** The shadow x-offset. */
093    private double shadowXOffset = 2.0;
094    
095    /** The shadow y-offset. */
096    private double shadowYOffset = 2.0;
097    
098    /** The text block. */
099    private TextBlock textBlock;
100
101    /**
102     * Creates an empty text box.
103     */
104    public TextBox() {
105        this((TextBlock) null);
106    }
107    
108    /**
109     * Creates a text box.
110     * 
111     * @param text  the text.
112     */
113    public TextBox(final String text) {
114        this((TextBlock) null);
115        if (text != null) {
116            this.textBlock = new TextBlock();
117            this.textBlock.addLine(
118                text, new Font("SansSerif", Font.PLAIN, 10), 
119                Color.black
120            );
121        }
122    }
123    
124    /**
125     * Creates a new text box.
126     * 
127     * @param block  the text block.
128     */
129    public TextBox(final TextBlock block) {
130        this.outlinePaint = Color.black;
131        this.outlineStroke = new BasicStroke(1.0f);
132        this.interiorGap = new RectangleInsets(1.0, 3.0, 1.0, 3.0);
133        this.backgroundPaint = new Color(255, 255, 192);
134        this.shadowPaint = Color.gray;
135        this.shadowXOffset = 2.0;
136        this.shadowYOffset = 2.0;
137        this.textBlock = block;      
138    }
139    
140    /**
141     * Returns the outline paint.
142     * 
143     * @return The outline paint.
144     */
145    public Paint getOutlinePaint() {
146        return this.outlinePaint;   
147    }
148    
149    /**
150     * Sets the outline paint.
151     * 
152     * @param paint  the paint.
153     */
154    public void setOutlinePaint(final Paint paint) {
155        this.outlinePaint = paint;   
156    }
157    
158    /**
159     * Returns the outline stroke.
160     * 
161     * @return The outline stroke.
162     */
163    public Stroke getOutlineStroke() {
164        return this.outlineStroke;   
165    }
166    
167    /**
168     * Sets the outline stroke.
169     * 
170     * @param stroke  the stroke.
171     */
172    public void setOutlineStroke(final Stroke stroke) {
173        this.outlineStroke = stroke;   
174    }
175    
176    /**
177     * Returns the interior gap.
178     * 
179     * @return The interior gap.
180     */
181    public RectangleInsets getInteriorGap() {
182        return this.interiorGap;   
183    }
184    
185    /**
186     * Sets the interior gap.
187     * 
188     * @param gap  the gap.
189     */
190    public void setInteriorGap(final RectangleInsets gap) {
191        this.interiorGap = gap;   
192    }
193    
194    /**
195     * Returns the background paint.
196     * 
197     * @return The background paint.
198     */
199    public Paint getBackgroundPaint() {
200        return this.backgroundPaint;   
201    }
202    
203    /**
204     * Sets the background paint.
205     * 
206     * @param paint  the paint.
207     */
208    public void setBackgroundPaint(final Paint paint) {
209        this.backgroundPaint = paint;   
210    }
211    
212    /**
213     * Returns the shadow paint.
214     * 
215     * @return The shadow paint.
216     */
217    public Paint getShadowPaint() {
218        return this.shadowPaint;   
219    }
220    
221    /**
222     * Sets the shadow paint.
223     * 
224     * @param paint  the paint.
225     */
226    public void setShadowPaint(final Paint paint) {
227        this.shadowPaint = paint;   
228    }
229    
230    /**
231     * Returns the x-offset for the shadow effect.
232     * 
233     * @return The offset.
234     */
235    public double getShadowXOffset() {
236        return this.shadowXOffset;   
237    }
238    
239    /**
240     * Sets the x-offset for the shadow effect.
241     * 
242     * @param offset  the offset (in Java2D units).
243     */
244    public void setShadowXOffset(final double offset) {
245        this.shadowXOffset = offset;   
246    }
247    
248    /**
249     * Returns the y-offset for the shadow effect.
250     * 
251     * @return The offset.
252     */
253    public double getShadowYOffset() {
254        return this.shadowYOffset;   
255    }
256    
257    /**
258     * Sets the y-offset for the shadow effect.
259     * 
260     * @param offset  the offset (in Java2D units).
261     */
262    public void setShadowYOffset(final double offset) {
263        this.shadowYOffset = offset;   
264    }
265    
266    /**
267     * Returns the text block.
268     * 
269     * @return The text block.
270     */
271    public TextBlock getTextBlock() {
272        return this.textBlock;   
273    }
274    
275    /**
276     * Sets the text block.
277     * 
278     * @param block  the block.
279     */
280    public void setTextBlock(final TextBlock block) {
281        this.textBlock = block;   
282    }
283    
284    /**
285     * Draws the text box.
286     * 
287     * @param g2  the graphics device.
288     * @param x  the x-coordinate.
289     * @param y  the y-coordinate.
290     * @param anchor  the anchor point.
291     */
292    public void draw(final Graphics2D g2, 
293                     final float x, final float y, 
294                     final RectangleAnchor anchor) {
295        final Size2D d1 = this.textBlock.calculateDimensions(g2);
296        final double w = this.interiorGap.extendWidth(d1.getWidth());
297        final double h = this.interiorGap.extendHeight(d1.getHeight());
298        final Size2D d2 = new Size2D(w, h);
299        final Rectangle2D bounds 
300            = RectangleAnchor.createRectangle(d2, x, y, anchor);
301        
302        if (this.shadowPaint != null) {
303            final Rectangle2D shadow = new Rectangle2D.Double(
304                bounds.getX() + this.shadowXOffset, 
305                bounds.getY() + this.shadowYOffset,
306                bounds.getWidth(), bounds.getHeight()
307            );
308            g2.setPaint(this.shadowPaint);
309            g2.fill(shadow);
310        }
311        if (this.backgroundPaint != null) {
312            g2.setPaint(this.backgroundPaint);
313            g2.fill(bounds);
314        }
315        
316        if (this.outlinePaint != null && this.outlineStroke != null) {
317            g2.setPaint(this.outlinePaint);
318            g2.setStroke(this.outlineStroke);
319            g2.draw(bounds);
320        }
321        
322        this.textBlock.draw(
323            g2, (float) bounds.getCenterX(), (float) bounds.getCenterY(), 
324            TextBlockAnchor.CENTER
325        );
326        
327    }
328    
329    /**
330     * Returns the height of the text box.
331     * 
332     * @param g2  the graphics device.
333     * 
334     * @return The height (in Java2D units).
335     */
336    public double getHeight(final Graphics2D g2) {
337        final Size2D d = this.textBlock.calculateDimensions(g2);
338        return this.interiorGap.extendHeight(d.getHeight());
339    }
340    
341    /**
342     * Tests this object for equality with an arbitrary object.
343     * 
344     * @param obj  the object to test against (<code>null</code> permitted).
345     * 
346     * @return A boolean.
347     */
348    public boolean equals(final Object obj) {
349        if (obj == this) {
350            return true;   
351        }
352        if (!(obj instanceof TextBox)) {
353            return false;
354        }
355        final TextBox that = (TextBox) obj;
356        if (!ObjectUtilities.equal(this.outlinePaint, that.outlinePaint)) {
357            return false;
358        }
359        if (!ObjectUtilities.equal(this.outlineStroke, that.outlineStroke)) {
360            return false;
361        }
362        if (!ObjectUtilities.equal(this.interiorGap, that.interiorGap)) {
363            return false;
364        }
365        if (!ObjectUtilities.equal(this.backgroundPaint, 
366                that.backgroundPaint)) {
367            return false;
368        }
369        if (!ObjectUtilities.equal(this.shadowPaint, that.shadowPaint)) {
370            return false;
371        }
372        if (this.shadowXOffset != that.shadowXOffset) {
373            return false;
374        }
375        if (this.shadowYOffset != that.shadowYOffset) {
376            return false;
377        }
378        if (!ObjectUtilities.equal(this.textBlock, that.textBlock)) {
379            return false;
380        }
381        
382        return true;
383    }
384
385    /**
386     * Returns a hash code for this object.
387     * 
388     * @return A hash code.
389     */
390    public int hashCode() {
391        int result;
392        long temp;
393        result = (this.outlinePaint != null ? this.outlinePaint.hashCode() : 0);
394        result = 29 * result + (this.outlineStroke != null 
395                ? this.outlineStroke.hashCode() : 0);
396        result = 29 * result + (this.interiorGap != null 
397                ? this.interiorGap.hashCode() : 0);
398        result = 29 * result + (this.backgroundPaint != null 
399                ? this.backgroundPaint.hashCode() : 0);
400        result = 29 * result + (this.shadowPaint != null 
401                ? this.shadowPaint.hashCode() : 0);
402        temp = this.shadowXOffset != +0.0d 
403                ? Double.doubleToLongBits(this.shadowXOffset) : 0L;
404        result = 29 * result + (int) (temp ^ (temp >>> 32));
405        temp = this.shadowYOffset != +0.0d 
406                ? Double.doubleToLongBits(this.shadowYOffset) : 0L;
407        result = 29 * result + (int) (temp ^ (temp >>> 32));
408        result = 29 * result + (this.textBlock != null 
409                ? this.textBlock.hashCode() : 0);
410        return result;
411    }
412
413    /**
414     * Provides serialization support.
415     *
416     * @param stream  the output stream.
417     *
418     * @throws IOException  if there is an I/O error.
419     */
420    private void writeObject(final ObjectOutputStream stream) 
421            throws IOException {
422        stream.defaultWriteObject();
423        SerialUtilities.writePaint(this.outlinePaint, stream);
424        SerialUtilities.writeStroke(this.outlineStroke, stream);
425        SerialUtilities.writePaint(this.backgroundPaint, stream);
426        SerialUtilities.writePaint(this.shadowPaint, stream);
427    }
428
429    /**
430     * Provides serialization support.
431     *
432     * @param stream  the input stream.
433     *
434     * @throws IOException  if there is an I/O error.
435     * @throws ClassNotFoundException  if there is a classpath problem.
436     */
437    private void readObject(final ObjectInputStream stream) 
438        throws IOException, ClassNotFoundException {
439        stream.defaultReadObject();
440        this.outlinePaint = SerialUtilities.readPaint(stream);
441        this.outlineStroke = SerialUtilities.readStroke(stream);
442        this.backgroundPaint = SerialUtilities.readPaint(stream);
443        this.shadowPaint = SerialUtilities.readPaint(stream);
444    }
445
446
447}