001: import java.awt.Font;
002: import java.awt.Graphics2D;
003: import java.awt.font.FontRenderContext;
004: import java.awt.geom.Line2D;
005: import java.awt.geom.Rectangle2D;
006: import java.io.Serializable;
007: import java.util.StringTokenizer;
008:
009: /**
010: A string that can extend over multiple lines.
011: */
012: public class MultiLineString implements Cloneable, Serializable
013: {
014: /**
015: Constructs an empty, centered, normal size multiline
016: string that is not underlined.
017: */
018: public MultiLineString()
019: {
020: text = "";
021: justification = CENTER;
022: size = NORMAL;
023: underlined = false;
024: }
025: /**
026: Sets the value of the text property.
027: @param newValue the text of the multiline string
028: */
029: public void setText(String newValue) { text = newValue; }
030: /**
031: Gets the value of the text property.
032: @return the text of the multiline string
033: */
034: public String getText() { return text; }
035: /**
036: Sets the value of the justification property.
037: @param newValue the justification, one of LEFT, CENTER,
038: RIGHT
039: */
040: public void setJustification(int newValue) { justification = newValue; }
041: /**
042: Gets the value of the justification property.
043: @return the justification, one of LEFT, CENTER,
044: RIGHT
045: */
046: public int getJustification() { return justification; }
047: /**
048: Gets the value of the underlined property.
049: @return true if the text is underlined
050: */
051: public boolean isUnderlined() { return underlined; }
052: /**
053: Sets the value of the underlined property.
054: @param newValue true to underline the text
055: */
056: public void setUnderlined(boolean newValue) { underlined = newValue; }
057: /**
058: Sets the value of the size property.
059: @param newValue the size, one of SMALL, NORMAL, LARGE
060: */
061: public void setSize(int newValue) { size = newValue; }
062: /**
063: Gets the value of the size property.
064: @return the size, one of SMALL, NORMAL, LARGE
065: */
066: public int getSize() { return size; }
067:
068: public String toString()
069: {
070: return text.replace('\n', '|');
071: }
072:
073: /**
074: Gets the bounding rectangle for this multiline string.
075: @param g2 the graphics context
076: @return the bounding rectangle (with top left corner (0,0))
077: */
078: public Rectangle2D getBounds(Graphics2D g2)
079: {
080: double width = 0;
081: double height = 0;
082: Font oldFont = g2.getFont();
083: Font font = oldFont;
084: if (size == LARGE)
085: {
086: float size = font.getSize() * 1.25F;
087: font = font.deriveFont(size);
088: }
089: else if (size == SMALL)
090: {
091: float size = font.getSize() / 1.25F;
092: font = font.deriveFont(size);
093: }
094: g2.setFont(font);
095: FontRenderContext frc = g2.getFontRenderContext();
096: StringTokenizer tokenizer = new StringTokenizer(text, "\n");
097: while (tokenizer.hasMoreTokens())
098: {
099: String t = tokenizer.nextToken();
100: Rectangle2D b = font.getStringBounds(t, frc);
101: width = Math.max(width, b.getWidth() + 2 * GAP);
102: height += b.getHeight();
103: }
104: g2.setFont(oldFont);
105: return new Rectangle2D.Double(0, 0, width, height);
106: }
107:
108: /**
109: Draws this multiline string inside a given rectangle
110: @param g2 the graphics context
111: @param r the rectangle into which to place this multiline string
112: */
113: public void draw(Graphics2D g2, Rectangle2D r)
114: {
115: Font oldFont = g2.getFont();
116: Font font = oldFont;
117: if (size == LARGE)
118: {
119: float size = font.getSize() * 1.25F;
120: font = font.deriveFont(size);
121: }
122: else if (size == SMALL)
123: {
124: float size = font.getSize() / 1.25F;
125: font = font.deriveFont(size);
126: }
127: g2.setFont(font);
128:
129: FontRenderContext frc = g2.getFontRenderContext();
130: Rectangle2D bounds = getBounds(g2);
131: StringTokenizer tokenizer = new StringTokenizer(text, "\n");
132: double xleft = r.getX();
133: double ytop = r.getY() + (r.getHeight() - bounds.getHeight()) / 2;
134: while (tokenizer.hasMoreTokens())
135: {
136: String t = tokenizer.nextToken();
137: Rectangle2D b = font.getStringBounds(t, frc);
138:
139: double xstart;
140: double xslack = r.getWidth() - b.getWidth();
141: if (justification == CENTER)
142: xstart = xleft + xslack / 2;
143: else if (justification == RIGHT)
144: xstart = xleft + xslack - GAP;
145: else
146: xstart = xleft + GAP;
147: double ystart = ytop - b.getY();
148: g2.drawString(t, (float)(xstart), (float)(ystart));
149: if (underlined)
150: g2.draw(new Line2D.Double(xstart, ystart + 1, xstart + b.getWidth(), ystart + 1));
151: ytop += b.getHeight();
152: }
153: g2.setFont(oldFont);
154: }
155:
156: public Object clone()
157: {
158: try
159: {
160: return super.clone();
161: }
162: catch (CloneNotSupportedException exception)
163: {
164: return null;
165: }
166: }
167:
168: public static final int LEFT = 0;
169: public static final int CENTER = 1;
170: public static final int RIGHT = 2;
171: public static final int LARGE = 3;
172: public static final int NORMAL = 4;
173: public static final int SMALL = 5;
174:
175: private static final int GAP = 3;
176:
177: private String text;
178: private int justification;
179: private int size;
180: private boolean underlined;
181: }