001: /* ===========================================================
002: * JFreeChart : a free chart library for the Java(tm) platform
003: * ===========================================================
004: *
005: * (C) Copyright 2000-2007, 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: * TextTitle.java
029: * --------------
030: * (C) Copyright 2000-2007, by David Berry and Contributors.
031: *
032: * Original Author: David Berry;
033: * Contributor(s): David Gilbert (for Object Refinery Limited);
034: * Nicolas Brodu;
035: *
036: * $Id: TextTitle.java,v 1.16.2.7 2007/04/04 10:44:11 mungady Exp $
037: *
038: * Changes (from 18-Sep-2001)
039: * --------------------------
040: * 18-Sep-2001 : Added standard header (DG);
041: * 07-Nov-2001 : Separated the JCommon Class Library classes, JFreeChart now
042: * requires jcommon.jar (DG);
043: * 09-Jan-2002 : Updated Javadoc comments (DG);
044: * 07-Feb-2002 : Changed Insets --> Spacer in AbstractTitle.java (DG);
045: * 06-Mar-2002 : Updated import statements (DG);
046: * 25-Jun-2002 : Removed redundant imports (DG);
047: * 18-Sep-2002 : Fixed errors reported by Checkstyle (DG);
048: * 28-Oct-2002 : Small modifications while changing JFreeChart class (DG);
049: * 13-Mar-2003 : Changed width used for relative spacing to fix bug 703050 (DG);
050: * 26-Mar-2003 : Implemented Serializable (DG);
051: * 15-Jul-2003 : Fixed null pointer exception (DG);
052: * 11-Sep-2003 : Implemented Cloneable (NB)
053: * 22-Sep-2003 : Added checks for null values and throw nullpointer
054: * exceptions (TM);
055: * Background paint was not serialized.
056: * 07-Oct-2003 : Added fix for exception caused by empty string in title (DG);
057: * 29-Oct-2003 : Added workaround for text alignment in PDF output (DG);
058: * 03-Feb-2004 : Fixed bug in getPreferredWidth() method (DG);
059: * 17-Feb-2004 : Added clone() method and fixed bug in equals() method (DG);
060: * 01-Apr-2004 : Changed java.awt.geom.Dimension2D to org.jfree.ui.Size2D
061: * because of JDK bug 4976448 which persists on JDK 1.3.1. Also
062: * fixed bug in getPreferredHeight() method (DG);
063: * 29-Apr-2004 : Fixed bug in getPreferredWidth() method - see bug id
064: * 944173 (DG);
065: * 11-Jan-2005 : Removed deprecated code in preparation for the 1.0.0
066: * release (DG);
067: * 08-Feb-2005 : Updated for changes in RectangleConstraint class (DG);
068: * 11-Feb-2005 : Implemented PublicCloneable (DG);
069: * 20-Apr-2005 : Added support for tooltips (DG);
070: * 26-Apr-2005 : Removed LOGGER (DG);
071: * 06-Jun-2005 : Modified equals() to handle GradientPaint (DG);
072: * 06-Jul-2005 : Added flag to control whether or not the title expands to
073: * fit the available space (DG);
074: * 07-Oct-2005 : Added textAlignment attribute (DG);
075: * ------------- JFREECHART 1.0.x RELEASED ------------------------------------
076: * 13-Dec-2005 : Fixed bug 1379331 - incorrect drawing with LEFT or RIGHT
077: * title placement (DG);
078: *
079: */
080:
081: package org.jfree.chart.title;
082:
083: import java.awt.Color;
084: import java.awt.Font;
085: import java.awt.Graphics2D;
086: import java.awt.Paint;
087: import java.awt.geom.Rectangle2D;
088: import java.io.IOException;
089: import java.io.ObjectInputStream;
090: import java.io.ObjectOutputStream;
091: import java.io.Serializable;
092:
093: import org.jfree.chart.block.BlockResult;
094: import org.jfree.chart.block.EntityBlockParams;
095: import org.jfree.chart.block.LengthConstraintType;
096: import org.jfree.chart.block.RectangleConstraint;
097: import org.jfree.chart.entity.ChartEntity;
098: import org.jfree.chart.entity.EntityCollection;
099: import org.jfree.chart.entity.StandardEntityCollection;
100: import org.jfree.chart.event.TitleChangeEvent;
101: import org.jfree.data.Range;
102: import org.jfree.io.SerialUtilities;
103: import org.jfree.text.G2TextMeasurer;
104: import org.jfree.text.TextBlock;
105: import org.jfree.text.TextBlockAnchor;
106: import org.jfree.text.TextUtilities;
107: import org.jfree.ui.HorizontalAlignment;
108: import org.jfree.ui.RectangleEdge;
109: import org.jfree.ui.RectangleInsets;
110: import org.jfree.ui.Size2D;
111: import org.jfree.ui.VerticalAlignment;
112: import org.jfree.util.ObjectUtilities;
113: import org.jfree.util.PaintUtilities;
114: import org.jfree.util.PublicCloneable;
115:
116: /**
117: * A chart title that displays a text string with automatic wrapping as
118: * required.
119: */
120: public class TextTitle extends Title implements Serializable,
121: Cloneable, PublicCloneable {
122:
123: /** For serialization. */
124: private static final long serialVersionUID = 8372008692127477443L;
125:
126: /** The default font. */
127: public static final Font DEFAULT_FONT = new Font("SansSerif",
128: Font.BOLD, 12);
129:
130: /** The default text color. */
131: public static final Paint DEFAULT_TEXT_PAINT = Color.black;
132:
133: /** The title text. */
134: private String text;
135:
136: /** The font used to display the title. */
137: private Font font;
138:
139: /** The text alignment. */
140: private HorizontalAlignment textAlignment;
141:
142: /** The paint used to display the title text. */
143: private transient Paint paint;
144:
145: /** The background paint. */
146: private transient Paint backgroundPaint;
147:
148: /** The tool tip text (can be <code>null</code>). */
149: private String toolTipText;
150:
151: /** The URL text (can be <code>null</code>). */
152: private String urlText;
153:
154: /** The content. */
155: private TextBlock content;
156:
157: /**
158: * A flag that controls whether the title expands to fit the available
159: * space..
160: */
161: private boolean expandToFitSpace = false;
162:
163: /**
164: * Creates a new title, using default attributes where necessary.
165: */
166: public TextTitle() {
167: this ("");
168: }
169:
170: /**
171: * Creates a new title, using default attributes where necessary.
172: *
173: * @param text the title text (<code>null</code> not permitted).
174: */
175: public TextTitle(String text) {
176: this (text, TextTitle.DEFAULT_FONT,
177: TextTitle.DEFAULT_TEXT_PAINT, Title.DEFAULT_POSITION,
178: Title.DEFAULT_HORIZONTAL_ALIGNMENT,
179: Title.DEFAULT_VERTICAL_ALIGNMENT, Title.DEFAULT_PADDING);
180: }
181:
182: /**
183: * Creates a new title, using default attributes where necessary.
184: *
185: * @param text the title text (<code>null</code> not permitted).
186: * @param font the title font (<code>null</code> not permitted).
187: */
188: public TextTitle(String text, Font font) {
189: this (text, font, TextTitle.DEFAULT_TEXT_PAINT,
190: Title.DEFAULT_POSITION,
191: Title.DEFAULT_HORIZONTAL_ALIGNMENT,
192: Title.DEFAULT_VERTICAL_ALIGNMENT, Title.DEFAULT_PADDING);
193: }
194:
195: /**
196: * Creates a new title.
197: *
198: * @param text the text for the title (<code>null</code> not permitted).
199: * @param font the title font (<code>null</code> not permitted).
200: * @param paint the title paint (<code>null</code> not permitted).
201: * @param position the title position (<code>null</code> not permitted).
202: * @param horizontalAlignment the horizontal alignment (<code>null</code>
203: * not permitted).
204: * @param verticalAlignment the vertical alignment (<code>null</code> not
205: * permitted).
206: * @param padding the space to leave around the outside of the title.
207: */
208: public TextTitle(String text, Font font, Paint paint,
209: RectangleEdge position,
210: HorizontalAlignment horizontalAlignment,
211: VerticalAlignment verticalAlignment, RectangleInsets padding) {
212:
213: super (position, horizontalAlignment, verticalAlignment, padding);
214:
215: if (text == null) {
216: throw new NullPointerException("Null 'text' argument.");
217: }
218: if (font == null) {
219: throw new NullPointerException("Null 'font' argument.");
220: }
221: if (paint == null) {
222: throw new NullPointerException("Null 'paint' argument.");
223: }
224: this .text = text;
225: this .font = font;
226: this .paint = paint;
227: // the textAlignment and the horizontalAlignment are separate things,
228: // but it makes sense for the default textAlignment to match the
229: // title's horizontal alignment...
230: this .textAlignment = horizontalAlignment;
231: this .backgroundPaint = null;
232: this .content = null;
233: this .toolTipText = null;
234: this .urlText = null;
235:
236: }
237:
238: /**
239: * Returns the title text.
240: *
241: * @return The text (never <code>null</code>).
242: *
243: * @see #setText(String)
244: */
245: public String getText() {
246: return this .text;
247: }
248:
249: /**
250: * Sets the title to the specified text and sends a
251: * {@link TitleChangeEvent} to all registered listeners.
252: *
253: * @param text the text (<code>null</code> not permitted).
254: */
255: public void setText(String text) {
256: if (text == null) {
257: throw new IllegalArgumentException("Null 'text' argument.");
258: }
259: if (!this .text.equals(text)) {
260: this .text = text;
261: notifyListeners(new TitleChangeEvent(this ));
262: }
263: }
264:
265: /**
266: * Returns the text alignment. This controls how the text is aligned
267: * within the title's bounds, whereas the title's horizontal alignment
268: * controls how the title's bounding rectangle is aligned within the
269: * drawing space.
270: *
271: * @return The text alignment.
272: */
273: public HorizontalAlignment getTextAlignment() {
274: return this .textAlignment;
275: }
276:
277: /**
278: * Sets the text alignment.
279: *
280: * @param alignment the alignment (<code>null</code> not permitted).
281: */
282: public void setTextAlignment(HorizontalAlignment alignment) {
283: if (alignment == null) {
284: throw new IllegalArgumentException(
285: "Null 'alignment' argument.");
286: }
287: this .textAlignment = alignment;
288: notifyListeners(new TitleChangeEvent(this ));
289: }
290:
291: /**
292: * Returns the font used to display the title string.
293: *
294: * @return The font (never <code>null</code>).
295: *
296: * @see #setFont(Font)
297: */
298: public Font getFont() {
299: return this .font;
300: }
301:
302: /**
303: * Sets the font used to display the title string. Registered listeners
304: * are notified that the title has been modified.
305: *
306: * @param font the new font (<code>null</code> not permitted).
307: *
308: * @see #getFont()
309: */
310: public void setFont(Font font) {
311: if (font == null) {
312: throw new IllegalArgumentException("Null 'font' argument.");
313: }
314: if (!this .font.equals(font)) {
315: this .font = font;
316: notifyListeners(new TitleChangeEvent(this ));
317: }
318: }
319:
320: /**
321: * Returns the paint used to display the title string.
322: *
323: * @return The paint (never <code>null</code>).
324: *
325: * @see #setPaint(Paint)
326: */
327: public Paint getPaint() {
328: return this .paint;
329: }
330:
331: /**
332: * Sets the paint used to display the title string. Registered listeners
333: * are notified that the title has been modified.
334: *
335: * @param paint the new paint (<code>null</code> not permitted).
336: *
337: * @see #getPaint()
338: */
339: public void setPaint(Paint paint) {
340: if (paint == null) {
341: throw new IllegalArgumentException("Null 'paint' argument.");
342: }
343: if (!this .paint.equals(paint)) {
344: this .paint = paint;
345: notifyListeners(new TitleChangeEvent(this ));
346: }
347: }
348:
349: /**
350: * Returns the background paint.
351: *
352: * @return The paint (possibly <code>null</code>).
353: */
354: public Paint getBackgroundPaint() {
355: return this .backgroundPaint;
356: }
357:
358: /**
359: * Sets the background paint and sends a {@link TitleChangeEvent} to all
360: * registered listeners. If you set this attribute to <code>null</code>,
361: * no background is painted (which makes the title background transparent).
362: *
363: * @param paint the background paint (<code>null</code> permitted).
364: */
365: public void setBackgroundPaint(Paint paint) {
366: this .backgroundPaint = paint;
367: notifyListeners(new TitleChangeEvent(this ));
368: }
369:
370: /**
371: * Returns the tool tip text.
372: *
373: * @return The tool tip text (possibly <code>null</code>).
374: */
375: public String getToolTipText() {
376: return this .toolTipText;
377: }
378:
379: /**
380: * Sets the tool tip text to the specified text and sends a
381: * {@link TitleChangeEvent} to all registered listeners.
382: *
383: * @param text the text (<code>null</code> permitted).
384: */
385: public void setToolTipText(String text) {
386: this .toolTipText = text;
387: notifyListeners(new TitleChangeEvent(this ));
388: }
389:
390: /**
391: * Returns the URL text.
392: *
393: * @return The URL text (possibly <code>null</code>).
394: */
395: public String getURLText() {
396: return this .urlText;
397: }
398:
399: /**
400: * Sets the URL text to the specified text and sends a
401: * {@link TitleChangeEvent} to all registered listeners.
402: *
403: * @param text the text (<code>null</code> permitted).
404: */
405: public void setURLText(String text) {
406: this .urlText = text;
407: notifyListeners(new TitleChangeEvent(this ));
408: }
409:
410: /**
411: * Returns the flag that controls whether or not the title expands to fit
412: * the available space.
413: *
414: * @return The flag.
415: */
416: public boolean getExpandToFitSpace() {
417: return this .expandToFitSpace;
418: }
419:
420: /**
421: * Sets the flag that controls whether the title expands to fit the
422: * available space, and sends a {@link TitleChangeEvent} to all registered
423: * listeners.
424: *
425: * @param expand the flag.
426: */
427: public void setExpandToFitSpace(boolean expand) {
428: this .expandToFitSpace = expand;
429: notifyListeners(new TitleChangeEvent(this ));
430: }
431:
432: /**
433: * Arranges the contents of the block, within the given constraints, and
434: * returns the block size.
435: *
436: * @param g2 the graphics device.
437: * @param constraint the constraint (<code>null</code> not permitted).
438: *
439: * @return The block size (in Java2D units, never <code>null</code>).
440: */
441: public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) {
442: RectangleConstraint cc = toContentConstraint(constraint);
443: LengthConstraintType w = cc.getWidthConstraintType();
444: LengthConstraintType h = cc.getHeightConstraintType();
445: Size2D contentSize = null;
446: if (w == LengthConstraintType.NONE) {
447: if (h == LengthConstraintType.NONE) {
448: throw new RuntimeException("Not yet implemented.");
449: } else if (h == LengthConstraintType.RANGE) {
450: throw new RuntimeException("Not yet implemented.");
451: } else if (h == LengthConstraintType.FIXED) {
452: throw new RuntimeException("Not yet implemented.");
453: }
454: } else if (w == LengthConstraintType.RANGE) {
455: if (h == LengthConstraintType.NONE) {
456: throw new RuntimeException("Not yet implemented.");
457: } else if (h == LengthConstraintType.RANGE) {
458: contentSize = arrangeRR(g2, cc.getWidthRange(), cc
459: .getHeightRange());
460: } else if (h == LengthConstraintType.FIXED) {
461: throw new RuntimeException("Not yet implemented.");
462: }
463: } else if (w == LengthConstraintType.FIXED) {
464: if (h == LengthConstraintType.NONE) {
465: throw new RuntimeException("Not yet implemented.");
466: } else if (h == LengthConstraintType.RANGE) {
467: throw new RuntimeException("Not yet implemented.");
468: } else if (h == LengthConstraintType.FIXED) {
469: throw new RuntimeException("Not yet implemented.");
470: }
471: }
472: return new Size2D(calculateTotalWidth(contentSize.getWidth()),
473: calculateTotalHeight(contentSize.getHeight()));
474: }
475:
476: /**
477: * Returns the content size for the title. This will reflect the fact that
478: * a text title positioned on the left or right of a chart will be rotated
479: * 90 degrees.
480: *
481: * @param g2 the graphics device.
482: * @param widthRange the width range.
483: * @param heightRange the height range.
484: *
485: * @return The content size.
486: */
487: protected Size2D arrangeRR(Graphics2D g2, Range widthRange,
488: Range heightRange) {
489: RectangleEdge position = getPosition();
490: if (position == RectangleEdge.TOP
491: || position == RectangleEdge.BOTTOM) {
492: float maxWidth = (float) widthRange.getUpperBound();
493: g2.setFont(this .font);
494: this .content = TextUtilities.createTextBlock(this .text,
495: this .font, this .paint, maxWidth,
496: new G2TextMeasurer(g2));
497: this .content.setLineAlignment(this .textAlignment);
498: Size2D contentSize = this .content.calculateDimensions(g2);
499: if (this .expandToFitSpace) {
500: return new Size2D(maxWidth, contentSize.getHeight());
501: } else {
502: return contentSize;
503: }
504: } else if (position == RectangleEdge.LEFT
505: || position == RectangleEdge.RIGHT) {
506: float maxWidth = (float) heightRange.getUpperBound();
507: g2.setFont(this .font);
508: this .content = TextUtilities.createTextBlock(this .text,
509: this .font, this .paint, maxWidth,
510: new G2TextMeasurer(g2));
511: this .content.setLineAlignment(this .textAlignment);
512: Size2D contentSize = this .content.calculateDimensions(g2);
513:
514: // transpose the dimensions, because the title is rotated
515: if (this .expandToFitSpace) {
516: return new Size2D(contentSize.getHeight(), maxWidth);
517: } else {
518: return new Size2D(contentSize.height, contentSize.width);
519: }
520: } else {
521: throw new RuntimeException("Unrecognised exception.");
522: }
523: }
524:
525: /**
526: * Draws the title on a Java 2D graphics device (such as the screen or a
527: * printer).
528: *
529: * @param g2 the graphics device.
530: * @param area the area allocated for the title.
531: */
532: public void draw(Graphics2D g2, Rectangle2D area) {
533: draw(g2, area, null);
534: }
535:
536: /**
537: * Draws the block within the specified area.
538: *
539: * @param g2 the graphics device.
540: * @param area the area.
541: * @param params if this is an instance of {@link EntityBlockParams} it
542: * is used to determine whether or not an
543: * {@link EntityCollection} is returned by this method.
544: *
545: * @return An {@link EntityCollection} containing a chart entity for the
546: * title, or <code>null</code>.
547: */
548: public Object draw(Graphics2D g2, Rectangle2D area, Object params) {
549: if (this .content == null) {
550: return null;
551: }
552: area = trimMargin(area);
553: drawBorder(g2, area);
554: if (this .text.equals("")) {
555: return null;
556: }
557: ChartEntity entity = null;
558: if (params instanceof EntityBlockParams) {
559: EntityBlockParams p = (EntityBlockParams) params;
560: if (p.getGenerateEntities()) {
561: entity = new ChartEntity(area, this .toolTipText,
562: this .urlText);
563: }
564: }
565: area = trimBorder(area);
566: if (this .backgroundPaint != null) {
567: g2.setPaint(this .backgroundPaint);
568: g2.fill(area);
569: }
570: area = trimPadding(area);
571: RectangleEdge position = getPosition();
572: if (position == RectangleEdge.TOP
573: || position == RectangleEdge.BOTTOM) {
574: drawHorizontal(g2, area);
575: } else if (position == RectangleEdge.LEFT
576: || position == RectangleEdge.RIGHT) {
577: drawVertical(g2, area);
578: }
579: BlockResult result = new BlockResult();
580: if (entity != null) {
581: StandardEntityCollection sec = new StandardEntityCollection();
582: sec.add(entity);
583: result.setEntityCollection(sec);
584: }
585: return result;
586: }
587:
588: /**
589: * Draws a the title horizontally within the specified area. This method
590: * will be called from the {@link #draw(Graphics2D, Rectangle2D) draw}
591: * method.
592: *
593: * @param g2 the graphics device.
594: * @param area the area for the title.
595: */
596: protected void drawHorizontal(Graphics2D g2, Rectangle2D area) {
597: Rectangle2D titleArea = (Rectangle2D) area.clone();
598: g2.setFont(this .font);
599: g2.setPaint(this .paint);
600: TextBlockAnchor anchor = null;
601: float x = 0.0f;
602: HorizontalAlignment horizontalAlignment = getHorizontalAlignment();
603: if (horizontalAlignment == HorizontalAlignment.LEFT) {
604: x = (float) titleArea.getX();
605: anchor = TextBlockAnchor.TOP_LEFT;
606: } else if (horizontalAlignment == HorizontalAlignment.RIGHT) {
607: x = (float) titleArea.getMaxX();
608: anchor = TextBlockAnchor.TOP_RIGHT;
609: } else if (horizontalAlignment == HorizontalAlignment.CENTER) {
610: x = (float) titleArea.getCenterX();
611: anchor = TextBlockAnchor.TOP_CENTER;
612: }
613: float y = 0.0f;
614: RectangleEdge position = getPosition();
615: if (position == RectangleEdge.TOP) {
616: y = (float) titleArea.getY();
617: } else if (position == RectangleEdge.BOTTOM) {
618: y = (float) titleArea.getMaxY();
619: if (horizontalAlignment == HorizontalAlignment.LEFT) {
620: anchor = TextBlockAnchor.BOTTOM_LEFT;
621: } else if (horizontalAlignment == HorizontalAlignment.CENTER) {
622: anchor = TextBlockAnchor.BOTTOM_CENTER;
623: } else if (horizontalAlignment == HorizontalAlignment.RIGHT) {
624: anchor = TextBlockAnchor.BOTTOM_RIGHT;
625: }
626: }
627: this .content.draw(g2, x, y, anchor);
628: }
629:
630: /**
631: * Draws a the title vertically within the specified area. This method
632: * will be called from the {@link #draw(Graphics2D, Rectangle2D) draw}
633: * method.
634: *
635: * @param g2 the graphics device.
636: * @param area the area for the title.
637: */
638: protected void drawVertical(Graphics2D g2, Rectangle2D area) {
639: Rectangle2D titleArea = (Rectangle2D) area.clone();
640: g2.setFont(this .font);
641: g2.setPaint(this .paint);
642: TextBlockAnchor anchor = null;
643: float y = 0.0f;
644: VerticalAlignment verticalAlignment = getVerticalAlignment();
645: if (verticalAlignment == VerticalAlignment.TOP) {
646: y = (float) titleArea.getY();
647: anchor = TextBlockAnchor.TOP_RIGHT;
648: } else if (verticalAlignment == VerticalAlignment.BOTTOM) {
649: y = (float) titleArea.getMaxY();
650: anchor = TextBlockAnchor.TOP_LEFT;
651: } else if (verticalAlignment == VerticalAlignment.CENTER) {
652: y = (float) titleArea.getCenterY();
653: anchor = TextBlockAnchor.TOP_CENTER;
654: }
655: float x = 0.0f;
656: RectangleEdge position = getPosition();
657: if (position == RectangleEdge.LEFT) {
658: x = (float) titleArea.getX();
659: } else if (position == RectangleEdge.RIGHT) {
660: x = (float) titleArea.getMaxX();
661: if (verticalAlignment == VerticalAlignment.TOP) {
662: anchor = TextBlockAnchor.BOTTOM_RIGHT;
663: } else if (verticalAlignment == VerticalAlignment.CENTER) {
664: anchor = TextBlockAnchor.BOTTOM_CENTER;
665: } else if (verticalAlignment == VerticalAlignment.BOTTOM) {
666: anchor = TextBlockAnchor.BOTTOM_LEFT;
667: }
668: }
669: this .content.draw(g2, x, y, anchor, x, y, -Math.PI / 2.0);
670: }
671:
672: /**
673: * Tests this title for equality with another object.
674: *
675: * @param obj the object (<code>null</code> permitted).
676: *
677: * @return <code>true</code> or <code>false</code>.
678: */
679: public boolean equals(Object obj) {
680: if (obj == this ) {
681: return true;
682: }
683: if (!(obj instanceof TextTitle)) {
684: return false;
685: }
686: if (!super .equals(obj)) {
687: return false;
688: }
689: TextTitle that = (TextTitle) obj;
690: if (!ObjectUtilities.equal(this .text, that.text)) {
691: return false;
692: }
693: if (!ObjectUtilities.equal(this .font, that.font)) {
694: return false;
695: }
696: if (!PaintUtilities.equal(this .paint, that.paint)) {
697: return false;
698: }
699: if (this .textAlignment != that.textAlignment) {
700: return false;
701: }
702: if (!PaintUtilities.equal(this .backgroundPaint,
703: that.backgroundPaint)) {
704: return false;
705: }
706: return true;
707: }
708:
709: /**
710: * Returns a hash code.
711: *
712: * @return A hash code.
713: */
714: public int hashCode() {
715: int result = super .hashCode();
716: result = 29 * result
717: + (this .text != null ? this .text.hashCode() : 0);
718: result = 29 * result
719: + (this .font != null ? this .font.hashCode() : 0);
720: result = 29 * result
721: + (this .paint != null ? this .paint.hashCode() : 0);
722: result = 29
723: * result
724: + (this .backgroundPaint != null ? this .backgroundPaint
725: .hashCode() : 0);
726: return result;
727: }
728:
729: /**
730: * Returns a clone of this object.
731: *
732: * @return A clone.
733: *
734: * @throws CloneNotSupportedException never.
735: */
736: public Object clone() throws CloneNotSupportedException {
737: return super .clone();
738: }
739:
740: /**
741: * Provides serialization support.
742: *
743: * @param stream the output stream.
744: *
745: * @throws IOException if there is an I/O error.
746: */
747: private void writeObject(ObjectOutputStream stream)
748: throws IOException {
749: stream.defaultWriteObject();
750: SerialUtilities.writePaint(this .paint, stream);
751: SerialUtilities.writePaint(this .backgroundPaint, stream);
752: }
753:
754: /**
755: * Provides serialization support.
756: *
757: * @param stream the input stream.
758: *
759: * @throws IOException if there is an I/O error.
760: * @throws ClassNotFoundException if there is a classpath problem.
761: */
762: private void readObject(ObjectInputStream stream)
763: throws IOException, ClassNotFoundException {
764: stream.defaultReadObject();
765: this.paint = SerialUtilities.readPaint(stream);
766: this.backgroundPaint = SerialUtilities.readPaint(stream);
767: }
768:
769: }
|