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