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: }