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.14 2008/09/01 16:00:42 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 }