KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > help > ui > internal > StyledLineWrapper


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.help.ui.internal;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Iterator JavaDoc;
15
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.custom.StyleRange;
18 import org.eclipse.swt.custom.StyledTextContent;
19 import org.eclipse.swt.custom.TextChangeListener;
20 import org.eclipse.swt.graphics.Drawable;
21 import org.eclipse.swt.graphics.GC;
22
23 import com.ibm.icu.text.BreakIterator;
24
25 public class StyledLineWrapper implements StyledTextContent {
26
27     /**
28      * Internal representation of <b> - unlikely to occur in a text
29      */

30     public static final String JavaDoc BOLD_CLOSE_TAG = "</@#$b>"; //$NON-NLS-1$
31
/**
32      * Internal representation of &lt;b&gt; - unlikely to occur in a text
33      */

34     public static final String JavaDoc BOLD_TAG = "<@#$b>"; //$NON-NLS-1$
35

36     private Drawable drawable;
37
38     /** Lines after splitting */
39     private ArrayList JavaDoc lines = new ArrayList JavaDoc();
40
41     /** Style ranges, per line */
42     private ArrayList JavaDoc lineStyleRanges = new ArrayList JavaDoc();
43
44     /** Character count */
45     private int charCount = -1;
46
47     /** Line breaker */
48     private static BreakIterator lineBreaker = BreakIterator.getLineInstance();
49
50     /** Beyond this length (pixels), lines should wrap */
51     public final static int DEFAULT_WIDTH = 350;
52
53     public int maxWidth;
54
55     /**
56      * Constructor
57      */

58     public StyledLineWrapper(String JavaDoc text, Drawable drawable, int minWidth) {
59         this.drawable = drawable;
60         maxWidth = Math.max(DEFAULT_WIDTH, minWidth);
61         if (text == null || text.length() == 0)
62             text = " "; // use one blank space //$NON-NLS-1$
63
setText(text);
64     }
65
66     /**
67      * @see StyledTextContent#addTextChangeListener(TextChangeListener)
68      */

69     public void addTextChangeListener(TextChangeListener l) {
70         // do nothing
71
}
72
73     /**
74      * @see StyledTextContent#getCharCount()
75      */

76     public int getCharCount() {
77         if (charCount != -1)
78             return charCount;
79         charCount = 0;
80         for (Iterator JavaDoc i = lines.iterator(); i.hasNext();)
81             charCount += ((String JavaDoc) i.next()).length();
82         return charCount;
83     }
84
85     /**
86      * @see StyledTextContent#getLine(int)
87      */

88     public String JavaDoc getLine(int i) {
89         if ((i >= lines.size()) || (i < 0))
90             SWT.error(SWT.ERROR_INVALID_ARGUMENT);
91         return (String JavaDoc) lines.get(i);
92     }
93
94     /**
95      * @see StyledTextContent#getLineAtOffset(int)
96      */

97     public int getLineAtOffset(int offset) {
98         if (offset >= getCharCount())
99             return getLineCount() - 1;
100         int count = 0;
101         int line = -1;
102         while (count <= offset) {
103             count += getLine(++line).length();
104         }
105         return line;
106     }
107
108     /**
109      * @see StyledTextContent#getLineCount()
110      */

111     public int getLineCount() {
112         if (lines.size() == 0)
113             return 1;
114         return lines.size();
115     }
116
117     /**
118      * @see StyledTextContent#getLineDelimiter()
119      */

120     public String JavaDoc getLineDelimiter() {
121         return null;
122     }
123
124     /**
125      * @see StyledTextContent#getOffsetAtLine(int)
126      */

127     public int getOffsetAtLine(int line) {
128         if (lines.size() == 0)
129             return 0;
130         int offset = 0;
131         for (int i = 0; i < line; i++)
132             offset += getLine(i).length();
133         return offset;
134     }
135
136     /**
137      * @see StyledTextContent#getTextRange(int, int)
138      */

139     public String JavaDoc getTextRange(int start, int end) {
140         int l1 = getLineAtOffset(start);
141         int l2 = getLineAtOffset(end);
142         if (l1 == l2)
143             return getLine(l1).substring(start - getOffsetAtLine(l1),
144                     end - start);
145         StringBuffer JavaDoc range = new StringBuffer JavaDoc(getLine(l1).substring(
146                 start - getOffsetAtLine(l1)));
147         for (int i = l1 + 1; i < l2; i++)
148             range.append(getLine(i));
149         range.append(getLine(l2).substring(0, end - getOffsetAtLine(l2)));
150         return range.toString();
151     }
152
153     /**
154      * @see StyledTextContent#removeTextChangeListener(TextChangeListener)
155      */

156     public void removeTextChangeListener(TextChangeListener arg0) {
157         // do nothing
158
}
159
160     /**
161      * @see StyledTextContent#replaceTextRange(int, int, String)
162      */

163     public void replaceTextRange(int arg0, int arg1, String JavaDoc arg2) {
164         // do nothing
165
}
166
167     /**
168      * @see StyledTextContent#setText(String)
169      */

170     public void setText(String JavaDoc text) {
171         if (text == null)
172             text = " "; //$NON-NLS-1$
173
processLineBreaks(text);
174         processStyles(text);
175     }
176
177     /**
178      * Returns the array of styles.
179      */

180     public StyleRange[] getStyles() {
181         StyleRange[] array = new StyleRange[lineStyleRanges.size()];
182         lineStyleRanges.toArray(array);
183         return array;
184     }
185
186     /**
187      * Create an array of lines with sytles stripped off. Each lines is at most
188      * MAX_LINE_LENGTH characters.
189      */

190     private void processLineBreaks(String JavaDoc text) {
191         // Create the original lines with style stripped
192
lines = new ArrayList JavaDoc();
193         char[] textChars = getUnstyledText(text).toCharArray();
194         int start = 0;
195         for (int i = start; i < textChars.length; i++) {
196             char ch = textChars[i];
197             if (ch == SWT.CR) {
198                 lines.add(new String JavaDoc(textChars, start, i - start));
199                 start = i + 1;
200                 // if we reached the end, stop
201
if (start >= textChars.length)
202                     break;
203                 { // see if the next character is an LF
204
ch = textChars[start];
205                     if (ch == SWT.LF) {
206                         start++;
207                         i++;
208                         if (start >= textChars.length)
209                             break;
210                     }
211                 }
212             } else if (ch == SWT.LF) {
213                 lines.add(new String JavaDoc(textChars, start, i - start));
214                 start = i + 1;
215                 if (start >= textChars.length)
216                     break;
217             } else if (i == textChars.length - 1) {
218                 lines.add(new String JavaDoc(textChars, start, i - start + 1));
219             }
220         }
221         // Break long lines
222
GC gc = new GC(drawable);
223         for (int i = 0; i < lines.size(); i++) {
224             String JavaDoc line = (String JavaDoc) lines.get(i);
225             while (line.length() > 0) {
226                 int linebreak = getLineBreak(line, gc);
227                 if (linebreak == 0 || linebreak == line.length())
228                     break;
229                 String JavaDoc newline = line.substring(0, linebreak);
230                 lines.remove(i);
231                 lines.add(i, newline);
232                 line = line.substring(linebreak);
233                 lines.add(++i, line);
234             }
235         }
236         gc.dispose();
237     }
238
239     /**
240      * Returns the text without the style
241      */

242     private static String JavaDoc getUnstyledText(String JavaDoc styledText) {
243         return styledText.replaceAll("</?@#\\$b>", ""); //$NON-NLS-1$ //$NON-NLS-2$
244
}
245
246     /**
247      * Finds a good line breaking point
248      */

249     private int getLineBreak(String JavaDoc line, GC gc) {
250         lineBreaker.setText(line);
251         int lastGoodIndex = 0;
252         int currentIndex = lineBreaker.first();
253         int width = gc.textExtent(line.substring(0, currentIndex)).x;
254         while (width < maxWidth && currentIndex != BreakIterator.DONE) {
255             lastGoodIndex = currentIndex;
256             currentIndex = lineBreaker.next();
257             if (currentIndex == BreakIterator.DONE) {
258                 break;
259             }
260             width = gc.textExtent(line.substring(0, currentIndex)).x;
261         }
262         return lastGoodIndex;
263     }
264
265     /**
266      * Creates all the (bold) style ranges for the text. It is assumed that the
267      * text has been split across lines.
268      */

269     private void processStyles(String JavaDoc text) {
270         // create a new array of styles
271
lineStyleRanges = new ArrayList JavaDoc();
272         // first, remove the line breaks
273
text = text.replaceAll("\n|\r", ""); //$NON-NLS-1$ //$NON-NLS-2$
274
int offset = 0;
275         do {
276             // create a style
277
StyleRange style = new StyleRange();
278             style.fontStyle = SWT.BOLD;
279             // the index of the starting style in styled text
280
int start = text.indexOf(BOLD_TAG, offset);
281             if (start == -1)
282                 break;
283             String JavaDoc prefix = getUnstyledText(text.substring(0, start));
284             style.start = prefix.length();
285             // the index of the ending style in styled text
286
offset = start + 1;
287             int end = text.indexOf(BOLD_CLOSE_TAG, offset);
288             if (end == -1)
289                 break;
290             prefix = getUnstyledText(text.substring(0, end));
291             style.length = prefix.length() - style.start;
292             lineStyleRanges.add(style);
293             offset = end + 1;
294         } while (offset < text.length());
295     }
296 }
297
Popular Tags