Source for org.jfree.text.TextBox

   1: /* ========================================================================
   2:  * JCommon : a free general purpose class library for the Java(tm) platform
   3:  * ========================================================================
   4:  *
   5:  * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
   6:  *
   7:  * Project Info:  http://www.jfree.org/jcommon/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it
  10:  * under the terms of the GNU Lesser General Public License as published by
  11:  * the Free Software Foundation; either version 2.1 of the License, or
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
  22:  * USA.
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  25:  * in the United States and other countries.]
  26:  *
  27:  * ------------
  28:  * TextBox.java
  29:  * ------------
  30:  * (C) Copyright 2004, 2008, by Object Refinery Limited and Contributors.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * $Id: TextBox.java,v 1.14 2008/09/01 16:00:42 mungady Exp $
  36:  *
  37:  * Changes
  38:  * -------
  39:  * 09-Mar-2004 : Version 1 (DG);
  40:  * 22-Mar-2004 : Added equals() method and implemented Serializable (DG);
  41:  * 09-Nov-2004 : Renamed getAdjustedHeight() --> calculateExtendedHeight() in
  42:  *               Spacer class (DG);
  43:  * 22-Feb-2005 : Replaced Spacer with RectangleInsets (DG);
  44:  * 14-Feb-2008 : Fixed alignment of text content with respect to insets (DG);
  45:  *
  46:  */
  47: 
  48: package org.jfree.text;
  49: 
  50: import java.awt.BasicStroke;
  51: import java.awt.Color;
  52: import java.awt.Font;
  53: import java.awt.Graphics2D;
  54: import java.awt.Paint;
  55: import java.awt.Stroke;
  56: import java.awt.geom.Rectangle2D;
  57: import java.io.IOException;
  58: import java.io.ObjectInputStream;
  59: import java.io.ObjectOutputStream;
  60: import java.io.Serializable;
  61: 
  62: import org.jfree.io.SerialUtilities;
  63: import org.jfree.ui.RectangleAnchor;
  64: import org.jfree.ui.RectangleInsets;
  65: import org.jfree.ui.Size2D;
  66: import org.jfree.util.ObjectUtilities;
  67: 
  68: /**
  69:  * A box containing a text block.
  70:  *
  71:  * @author David Gilbert
  72:  */
  73: public class TextBox implements Serializable {
  74: 
  75:     /** For serialization. */
  76:     private static final long serialVersionUID = 3360220213180203706L;
  77: 
  78:     /** The outline paint. */
  79:     private transient Paint outlinePaint;
  80: 
  81:     /** The outline stroke. */
  82:     private transient Stroke outlineStroke;
  83: 
  84:     /** The interior space. */
  85:     private RectangleInsets interiorGap;
  86: 
  87:     /** The background paint. */
  88:     private transient Paint backgroundPaint;
  89: 
  90:     /** The shadow paint. */
  91:     private transient Paint shadowPaint;
  92: 
  93:     /** The shadow x-offset. */
  94:     private double shadowXOffset = 2.0;
  95: 
  96:     /** The shadow y-offset. */
  97:     private double shadowYOffset = 2.0;
  98: 
  99:     /** 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: }