Source code: com/flexstor/common/awt/field/WrappingLabel.java
1 /*
2 * WrappingLabel.java
3 *
4 * Copyright $Date: 2003/08/12 04:19:53 $ FLEXSTOR.net Inc.
5 *
6 * This work is licensed for use and distribution under license terms found at
7 * http://www.flexstor.org/license.html
8 *
9 */
10
11 package com.flexstor.common.awt.field;
12
13 import java.awt.Canvas;
14 import java.awt.Dimension;
15 import java.awt.FontMetrics;
16
17 /**
18 * This class displays lines of text and wraps them around.
19 * To work properly, one dimension (width or height) must be set
20 * with setPreferredWidth/Height methods. The other dimension will
21 * be calculated.
22 */
23 public class WrappingLabel extends Canvas
24 {
25 protected Dimension dimPreferred = new Dimension(-1, -1);
26
27 protected String text = "";
28
29 protected int align = ALIGN_LEFT;
30
31 protected int baseline;
32
33 transient protected FontMetrics fm;
34 public static final int ALIGN_LEFT = 0;
35 public static final int ALIGN_CENTERED = 1;
36 public static final int ALIGN_RIGHT = 2;
37
38
39 /**
40 * This method returns reasonable values after addNotify has been called.
41 * This works fine when a layout manager is used, otherwise the method
42 * should be called AFTER the peer is realized.
43 */
44 public Dimension getPreferredSize()
45 {
46 if (dimPreferred.width > 0 && dimPreferred.height > 0)
47 // both values valid, return that dimension
48 return new Dimension(dimPreferred);
49
50 else if (dimPreferred.width < 0 && dimPreferred.height < 0)
51 // default, neither width nor height set
52 return new Dimension(100,25);
53
54 else if (dimPreferred.height < 0)
55 //calculate height
56 dimPreferred.height = calculatePreferredHeight(dimPreferred.width);
57
58 else if (dimPreferred.width < 0)
59 //calculate width
60 dimPreferred.width = calculatePreferredWidth(dimPreferred.height);
61
62 return new Dimension(dimPreferred);
63
64 // use parent's width as basis for height calculation
65 //return new Dimension(getParent().getSize().width, calculatePreferredHeight(getParent().getSize().width));
66 }
67
68 public Dimension getMinimumSize()
69 {
70 return getPreferredSize();
71 }
72
73 // for compatibility with JDK 1.0 layout managers
74 //public Dimension minimumSize() {return getMinimumSize();}
75 //public Dimension preferredSize() {return getPreferredSize();}
76
77 /**
78 * Sets the preferred width. The height will be calculated.
79 * @param the new preferred width
80 */
81 public void setPreferredWidth(int width)
82 {
83 dimPreferred.width = width;
84 dimPreferred.height = -1; // indicates need to recalculate
85 }
86
87 /**
88 * Sets the preferred height. The width will be calculated.
89 * @param the new preferred height
90 */
91 public void setPreferredHeight(int height)
92 {
93 dimPreferred.height = height;
94 dimPreferred.width = -1; // indicates need to recalculate
95 }
96
97 /**
98 * Calculates width for a given height. This only works approximate
99 * because stringWidth does not consider line breaks etc.
100 * For now, there is no need to improve this method.
101 */
102 protected int calculatePreferredWidth(int nHeight)
103 {
104 if (text == null || nHeight < 0 || getFont() == null)
105 return -1;
106
107 fm = getToolkit().getFontMetrics(getFont());
108 int nLines = (nHeight / fm.getHeight()) + 1;
109 return fm.stringWidth(text) / nLines;
110 }
111
112 /**
113 * Calculates height for a given width.
114 * (modified code from Symantec's paint method)
115 */
116 protected int calculatePreferredHeight(int nWidth)
117 {
118 int y = -1;
119
120 if (text != null && nWidth > 0 && getFont() != null)
121 {
122 int fromIndex = 0;
123 int pos = 0;
124 int bestpos;
125 String largestString;
126 String s;
127
128 fm = getToolkit().getFontMetrics(getFont());
129 baseline = fm.getMaxAscent();
130
131 // X and Y represent the coordinates of the upper left portion
132 // of the next text line.
133 y = 0;
134
135 while (fromIndex != -1)
136 {
137 // Automatically skip any spaces at the beginning of the line
138 while (fromIndex < text.length() && text.charAt(fromIndex) == ' ')
139 {
140 ++fromIndex;
141 // If we hit the end of line while skipping spaces, we're done.
142 if (fromIndex >= text.length()) break;
143 }
144
145 // fromIndex represents the beginning of the line
146 pos = fromIndex;
147 bestpos = -1;
148 largestString = null;
149
150 while (pos >= fromIndex)
151 {
152 pos = text.indexOf(' ', pos);
153 // Couldn't find another space?
154 if (pos == -1)
155 {
156 s = text.substring(fromIndex);
157 }
158 else
159 {
160 s = text.substring(fromIndex, pos);
161 }
162 // If the string fits, keep track of it.
163 if (fm.stringWidth(s) < nWidth)
164 {
165 largestString = s;
166 bestpos = pos;
167 // If we've hit the end of the string, use it.
168 if (pos == -1) break;
169 }
170 else
171 {
172 break;
173 }
174
175 ++pos;
176 }
177
178 if (largestString == null)
179 {
180 // Couldn't wrap at a space, so find the largest line
181 // that fits and print that. Note that this will be
182 // slightly off -- the width of a string will not necessarily
183 // be the sum of the width of its characters, due to kerning.
184 int totalWidth = 0;
185 int oneCharWidth = 0;
186
187 pos = fromIndex;
188
189 while (pos < text.length())
190 {
191 oneCharWidth = fm.charWidth(text.charAt(pos));
192 if ((totalWidth + oneCharWidth) >= nWidth) break;
193 totalWidth += oneCharWidth;
194 ++pos;
195 }
196
197 //RD drawAlignedString(g, text.substring(fromIndex, pos), x, y, nWidth);
198 fromIndex = pos;
199 }
200 else
201 {
202 //RD drawAlignedString(g, largestString, x, y, nWidth);
203
204 fromIndex = bestpos;
205 }
206 y += fm.getHeight();
207 }
208
209 // We're done with the font metrics...
210 //RD fm = null;
211 }
212 return y;
213 }
214
215 public void setText(String newText)
216 {
217 text = newText;
218 repaint();
219 }
220
221 public void setAlignStyle(int newAlignStyle)
222 {
223 if (align != newAlignStyle)
224 {
225 align = newAlignStyle;
226 repaint();
227 }
228 }
229
230 }