Mercurial > projects > dwt-mac
comparison dwt/custom/DefaultContent.d @ 41:6337764516f1
Sync dwt/custom with dwt-linux (took copy of complete folder)
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Tue, 07 Oct 2008 16:29:55 +0200 |
parents | e831403a80a9 |
children |
comparison
equal
deleted
inserted
replaced
40:fbe68c33eeee | 41:6337764516f1 |
---|---|
1 /******************************************************************************* | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2007 IBM Corporation and others. | 2 * Copyright (c) 2000, 2008 IBM Corporation and others. |
3 * All rights reserved. This program and the accompanying materials | 3 * All rights reserved. This program and the accompanying materials |
4 * are made available under the terms of the Eclipse Public License v1.0 | 4 * are made available under the terms of the Eclipse Public License v1.0 |
5 * which accompanies this distribution, and is available at | 5 * which accompanies this distribution, and is available at |
6 * http://www.eclipse.org/legal/epl-v10.html | 6 * http://www.eclipse.org/legal/epl-v10.html |
7 * | 7 * |
8 * Contributors: | 8 * Contributors: |
9 * IBM Corporation - initial API and implementation | 9 * IBM Corporation - initial API and implementation |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
10 *******************************************************************************/ | 12 *******************************************************************************/ |
11 module dwt.custom; | 13 module dwt.custom.DefaultContent; |
12 | 14 |
13 import dwt.*; | 15 import dwt.DWT; |
16 import dwt.DWTException; | |
14 import dwt.internal.Compatibility; | 17 import dwt.internal.Compatibility; |
15 import dwt.widgets.*; | 18 import dwt.widgets.TypedListener; |
16 import java.util.Vector; | 19 import dwt.custom.StyledTextContent; |
20 import dwt.custom.TextChangeListener; | |
21 import dwt.custom.StyledTextEvent; | |
22 import dwt.custom.StyledTextListener; | |
23 import dwt.custom.StyledText; | |
24 import dwt.dwthelper.utils; | |
25 | |
26 static import tango.io.model.IFile; | |
27 static import tango.text.Text; | |
28 | |
29 alias tango.text.Text.Text!(char) StringBuffer; | |
17 | 30 |
18 class DefaultContent : StyledTextContent { | 31 class DefaultContent : StyledTextContent { |
19 private final static String LineDelimiter = System.getProperty("line.separator"); | 32 private final static String LineDelimiter = tango.io.model.IFile.FileConst.NewlineString; |
20 | 33 |
21 Vector textListeners = new Vector(); // stores text listeners for event sending | 34 StyledTextListener[] textListeners; // stores text listeners for event sending |
22 char[] textStore = new char[0]; // stores the actual text | 35 char[] textStore; // stores the actual text |
23 int gapStart = -1; // the character position start of the gap | 36 int gapStart = -1; // the character position start of the gap |
24 int gapEnd = -1; // the character position after the end of the gap | 37 int gapEnd = -1; // the character position after the end of the gap |
25 int gapLine = -1; // the line on which the gap exists, the gap will always be associated with one line | 38 int gapLine = -1; // the line on which the gap exists, the gap will always be associated with one line |
26 int highWatermark = 300; | 39 int highWatermark = 300; |
27 int lowWatermark = 50; | 40 int lowWatermark = 50; |
28 | 41 |
29 int[][] lines = new int[50][2]; // array of character positions and lengths representing the lines of text | 42 int[][] lines; // array of character positions and lengths representing the lines of text |
30 int lineCount = 0; // the number of lines of text | 43 int lineCount_ = 0; // the number of lines of text |
31 int expandExp = 1; // the expansion exponent, used to increase the lines array exponentially | 44 int expandExp = 1; // the expansion exponent, used to increase the lines array exponentially |
32 int replaceExpandExp = 1; // the expansion exponent, used to increase the lines array exponentially | 45 int replaceExpandExp = 1; // the expansion exponent, used to increase the lines array exponentially |
33 | 46 |
34 /** | 47 /** |
35 * Creates a new DefaultContent and initializes it. A <code>StyledTextContent</> will always have | 48 * Creates a new DefaultContent and initializes it. A <code>StyledTextContent</> will always have |
36 * at least one empty line. | 49 * at least one empty line. |
37 */ | 50 */ |
38 this() { | 51 this() { |
39 super(); | 52 lines = new int[][]( 50, 2 ); |
40 setText(""); | 53 setText(""); |
41 } | 54 } |
42 /** | 55 /** |
43 * Adds a line to the end of the line indexes array. Increases the size of the array if necessary. | 56 * Adds a line to the end of the line indexes array. Increases the size of the array if necessary. |
44 * <code>lineCount</code> is updated to reflect the new entry. | 57 * <code>lineCount</code> is updated to reflect the new entry. |
45 * <p> | 58 * <p> |
46 * | 59 * |
47 * @param start the start of the line | 60 * @param start the start of the line |
48 * @param length the length of the line | 61 * @param length the length of the line |
49 */ | 62 */ |
50 void addLineIndex(int start, int length) { | 63 void addLineIndex(int start, int length) { |
51 int size = lines.length; | 64 int size = lines.length; |
52 if (lineCount is size) { | 65 if (lineCount_ is size) { |
53 // expand the lines by powers of 2 | 66 // expand the lines by powers of 2 |
54 int[][] newLines = new int[size+Compatibility.pow2(expandExp)][2]; | 67 int[][] newLines = new int[][]( size+Compatibility.pow2(expandExp), 2 ); |
55 System.arraycopy(lines, 0, newLines, 0, size); | 68 System.arraycopy(lines, 0, newLines, 0, size); |
56 lines = newLines; | 69 lines = newLines; |
57 expandExp++; | 70 expandExp++; |
58 } | 71 } |
59 int[] range = new int[] {start, length}; | 72 int[] range = [start, length]; |
60 lines[lineCount] = range; | 73 lines[lineCount_] = range; |
61 lineCount++; | 74 lineCount_++; |
62 } | 75 } |
63 /** | 76 /** |
64 * Adds a line index to the end of <code>linesArray</code>. Increases the | 77 * Adds a line index to the end of <code>linesArray</code>. Increases the |
65 * size of the array if necessary and returns a new array. | 78 * size of the array if necessary and returns a new array. |
66 * <p> | 79 * <p> |
67 * | 80 * |
68 * @param start the start of the line | 81 * @param start the start of the line |
69 * @param length the length of the line | 82 * @param length the length of the line |
73 */ | 86 */ |
74 int[][] addLineIndex(int start, int length, int[][] linesArray, int count) { | 87 int[][] addLineIndex(int start, int length, int[][] linesArray, int count) { |
75 int size = linesArray.length; | 88 int size = linesArray.length; |
76 int[][] newLines = linesArray; | 89 int[][] newLines = linesArray; |
77 if (count is size) { | 90 if (count is size) { |
78 newLines = new int[size+Compatibility.pow2(replaceExpandExp)][2]; | 91 newLines = new int[][]( size+Compatibility.pow2(replaceExpandExp), 2 ); |
79 replaceExpandExp++; | 92 replaceExpandExp++; |
80 System.arraycopy(linesArray, 0, newLines, 0, size); | 93 System.arraycopy(linesArray, 0, newLines, 0, size); |
81 } | 94 } |
82 int[] range = new int[] {start, length}; | 95 int[] range = [start, length]; |
83 newLines[count] = range; | 96 newLines[count] = range; |
84 return newLines; | 97 return newLines; |
85 } | 98 } |
86 /** | 99 /** |
87 * Adds a <code>TextChangeListener</code> listening for | 100 * Adds a <code>TextChangeListener</code> listening for |
88 * <code>TextChangingEvent</code> and <code>TextChangedEvent</code>. A | 101 * <code>TextChangingEvent</code> and <code>TextChangedEvent</code>. A |
89 * <code>TextChangingEvent</code> is sent before changes to the text occur. | 102 * <code>TextChangingEvent</code> is sent before changes to the text occur. |
90 * A <code>TextChangedEvent</code> is sent after changes to the text | 103 * A <code>TextChangedEvent</code> is sent after changes to the text |
91 * occurred. | 104 * occurred. |
92 * <p> | 105 * <p> |
93 * | 106 * |
94 * @param listener the listener | 107 * @param listener the listener |
95 * @exception IllegalArgumentException <ul> | 108 * @exception IllegalArgumentException <ul> |
97 * </ul> | 110 * </ul> |
98 */ | 111 */ |
99 public void addTextChangeListener(TextChangeListener listener) { | 112 public void addTextChangeListener(TextChangeListener listener) { |
100 if (listener is null) error(DWT.ERROR_NULL_ARGUMENT); | 113 if (listener is null) error(DWT.ERROR_NULL_ARGUMENT); |
101 StyledTextListener typedListener = new StyledTextListener(listener); | 114 StyledTextListener typedListener = new StyledTextListener(listener); |
102 textListeners.addElement(typedListener); | 115 textListeners ~= typedListener; |
103 } | 116 } |
104 /** | 117 /** |
105 * Adjusts the gap to accommodate a text change that is occurring. | 118 * Adjusts the gap to accommodate a text change that is occurring. |
106 * <p> | 119 * <p> |
107 * | 120 * |
108 * @param position the position at which a change is occurring | 121 * @param position the position at which a change is occurring |
122 return; | 135 return; |
123 } | 136 } |
124 moveAndResizeGap(position, sizeHint, line); | 137 moveAndResizeGap(position, sizeHint, line); |
125 } | 138 } |
126 /** | 139 /** |
127 * Calculates the indexes of each line in the text store. Assumes no gap exists. | 140 * Calculates the indexes of each line in the text store. Assumes no gap exists. |
128 * Optimized to do less checking. | 141 * Optimized to do less checking. |
129 */ | 142 */ |
130 void indexLines(){ | 143 void indexLines(){ |
131 int start = 0; | 144 int start = 0; |
132 lineCount = 0; | 145 lineCount_ = 0; |
133 int textLength = textStore.length; | 146 int textLength = textStore.length; |
134 int i; | 147 int i; |
135 for (i = start; i < textLength; i++) { | 148 for (i = start; i < textLength; i++) { |
136 char ch = textStore[i]; | 149 char ch = textStore[i]; |
137 if (ch is DWT.CR) { | 150 if (ch is DWT.CR) { |
138 // see if the next character is a LF | 151 // see if the next character is a LF |
139 if (i + 1 < textLength) { | 152 if (i + 1 < textLength) { |
140 ch = textStore[i+1]; | 153 ch = textStore[i+1]; |
141 if (ch is DWT.LF) { | 154 if (ch is DWT.LF) { |
149 start = i + 1; | 162 start = i + 1; |
150 } | 163 } |
151 } | 164 } |
152 addLineIndex(start, i - start); | 165 addLineIndex(start, i - start); |
153 } | 166 } |
154 /** | 167 /** |
155 * Returns whether or not the given character is a line delimiter. Both CR and LF | 168 * Returns whether or not the given character is a line delimiter. Both CR and LF |
156 * are valid line delimiters. | 169 * are valid line delimiters. |
157 * <p> | 170 * <p> |
158 * | 171 * |
159 * @param ch the character to test | 172 * @param ch the character to test |
160 * @return true if ch is a delimiter, false otherwise | 173 * @return true if ch is a delimiter, false otherwise |
161 */ | 174 */ |
162 bool isDelimiter(char ch) { | 175 bool isDelimiter(char ch) { |
163 if (ch is DWT.CR) return true; | 176 if (ch is DWT.CR) return true; |
164 if (ch is DWT.LF) return true; | 177 if (ch is DWT.LF) return true; |
165 return false; | 178 return false; |
166 } | 179 } |
167 /** | 180 /** |
168 * Determine whether or not the replace operation is valid. DefaultContent will not allow | 181 * Determine whether or not the replace operation is valid. DefaultContent will not allow |
169 * the /r/n line delimiter to be split or partially deleted. | 182 * the /r/n line delimiter to be split or partially deleted. |
170 * <p> | 183 * <p> |
171 * | 184 * |
177 protected bool isValidReplace(int start, int replaceLength, String newText){ | 190 protected bool isValidReplace(int start, int replaceLength, String newText){ |
178 if (replaceLength is 0) { | 191 if (replaceLength is 0) { |
179 // inserting text, see if the \r\n line delimiter is being split | 192 // inserting text, see if the \r\n line delimiter is being split |
180 if (start is 0) return true; | 193 if (start is 0) return true; |
181 if (start is getCharCount()) return true; | 194 if (start is getCharCount()) return true; |
182 char before = getTextRange(start - 1, 1).charAt(0); | 195 char before = getTextRange(start - 1, 1)[0]; |
183 if (before is '\r') { | 196 if (before is '\r') { |
184 char after = getTextRange(start, 1).charAt(0); | 197 char after = getTextRange(start, 1)[0]; |
185 if (after is '\n') return false; | 198 if (after is '\n') return false; |
186 } | 199 } |
187 } else { | 200 } else { |
188 // deleting text, see if part of a \r\n line delimiter is being deleted | 201 // deleting text, see if part of a \r\n line delimiter is being deleted |
189 char startChar = getTextRange(start, 1).charAt(0); | 202 char startChar = getTextRange(start, 1)[0]; |
190 if (startChar is '\n') { | 203 if (startChar is '\n') { |
191 // see if char before delete position is \r | 204 // see if char before delete position is \r |
192 if (start !is 0) { | 205 if (start !is 0) { |
193 char before = getTextRange(start - 1, 1).charAt(0); | 206 char before = getTextRange(start - 1, 1)[0]; |
194 if (before is '\r') return false; | 207 if (before is '\r') return false; |
195 } | 208 } |
196 } | 209 } |
197 char endChar = getTextRange(start + replaceLength - 1, 1).charAt(0); | 210 char endChar = getTextRange(start + replaceLength - 1, 1)[0]; |
198 if (endChar is '\r') { | 211 if (endChar is '\r') { |
199 // see if char after delete position is \n | 212 // see if char after delete position is \n |
200 if (start + replaceLength !is getCharCount()) { | 213 if (start + replaceLength !is getCharCount()) { |
201 char after = getTextRange(start + replaceLength, 1).charAt(0); | 214 char after = getTextRange(start + replaceLength, 1)[0]; |
202 if (after is '\n') return false; | 215 if (after is '\n') return false; |
203 } | 216 } |
204 } | 217 } |
205 } | 218 } |
206 return true; | 219 return true; |
207 } | 220 } |
208 /** | 221 /** |
209 * Calculates the indexes of each line of text in the given range. | 222 * Calculates the indexes of each line of text in the given range. |
210 * <p> | 223 * <p> |
211 * | 224 * |
212 * @param offset the logical start offset of the text lineate | 225 * @param offset the logical start offset of the text lineate |
213 * @param length the length of the text to lineate, includes gap | 226 * @param length the length of the text to lineate, includes gap |
214 * @param numLines the number of lines to initially allocate for the line index array, | 227 * @param numLines the number of lines to initially allocate for the line index array, |
215 * passed in for efficiency (the exact number of lines may be known) | 228 * passed in for efficiency (the exact number of lines may be known) |
216 * @return a line indexes array where each line is identified by a start offset and | 229 * @return a line indexes array where each line is identified by a start offset and |
217 * a length | 230 * a length |
218 */ | 231 */ |
219 int[][] indexLines(int offset, int length, int numLines){ | 232 int[][] indexLines(int offset, int length, int numLines){ |
220 int[][] indexedLines = new int[numLines][2]; | 233 int[][] indexedLines = new int[][]( numLines, 2 ); |
221 int start = 0; | 234 int start = 0; |
222 int lineCount = 0; | 235 int lineCount_ = 0; |
223 int i; | 236 int i; |
224 replaceExpandExp = 1; | 237 replaceExpandExp = 1; |
225 for (i = start; i < length; i++) { | 238 for (i = start; i < length; i++) { |
226 int location = i + offset; | 239 int location = i + offset; |
227 if ((location >= gapStart) && (location < gapEnd)) { | 240 if ((location >= gapStart) && (location < gapEnd)) { |
228 // ignore the gap | 241 // ignore the gap |
229 } else { | 242 } else { |
230 char ch = textStore[location]; | 243 char ch = textStore[location]; |
231 if (ch is DWT.CR) { | 244 if (ch is DWT.CR) { |
232 // see if the next character is a LF | 245 // see if the next character is a LF |
233 if (location+1 < textStore.length) { | 246 if (location+1 < textStore.length) { |
234 ch = textStore[location+1]; | 247 ch = textStore[location+1]; |
235 if (ch is DWT.LF) { | 248 if (ch is DWT.LF) { |
236 i++; | 249 i++; |
237 } | 250 } |
238 } | 251 } |
239 indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount); | 252 indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount_); |
240 lineCount++; | 253 lineCount_++; |
241 start = i + 1; | 254 start = i + 1; |
242 } else if (ch is DWT.LF) { | 255 } else if (ch is DWT.LF) { |
243 indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount); | 256 indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount_); |
244 lineCount++; | 257 lineCount_++; |
245 start = i + 1; | 258 start = i + 1; |
246 } | 259 } |
247 } | 260 } |
248 } | 261 } |
249 int[][] newLines = new int[lineCount+1][2]; | 262 int[][] newLines = new int[][]( lineCount_+1, 2 ); |
250 System.arraycopy(indexedLines, 0, newLines, 0, lineCount); | 263 System.arraycopy(indexedLines, 0, newLines, 0, lineCount_); |
251 int[] range = new int[] {start, i - start}; | 264 int[] range = [start, i - start]; |
252 newLines[lineCount] = range; | 265 newLines[lineCount_] = range; |
253 return newLines; | 266 return newLines; |
254 } | 267 } |
255 /** | 268 /** |
256 * Inserts text. | 269 * Inserts text. |
257 * <p> | 270 * <p> |
258 * | 271 * |
259 * @param position the position at which to insert the text | 272 * @param position the position at which to insert the text |
260 * @param text the text to insert | 273 * @param text the text to insert |
261 */ | 274 */ |
262 void insert(int position, String text) { | 275 void insert(int position, String text) { |
263 if (text.length() is 0) return; | 276 if (text.length is 0) return; |
264 | 277 |
265 int startLine = getLineAtOffset(position); | 278 int startLine = getLineAtOffset(position); |
266 int change = text.length(); | 279 int change = text.length; |
267 bool endInsert = position is getCharCount(); | 280 bool endInsert = position is getCharCount(); |
268 adjustGap(position, change, startLine); | 281 adjustGap(position, change, startLine); |
269 | 282 |
270 // during an insert the gap will be adjusted to start at | 283 // during an insert the gap will be adjusted to start at |
271 // position and it will be associated with startline, the | 284 // position and it will be associated with startline, the |
272 // inserted text will be placed in the gap | 285 // inserted text will be placed in the gap |
273 int startLineOffset = getOffsetAtLine(startLine); | 286 int startLineOffset = getOffsetAtLine(startLine); |
274 // at this point, startLineLength will include the start line | 287 // at this point, startLineLength will include the start line |
275 // and all of the newly inserted text | 288 // and all of the newly inserted text |
276 int startLineLength = getPhysicalLine(startLine).length(); | 289 int startLineLength = getPhysicalLine(startLine).length; |
277 | 290 |
278 if (change > 0) { | 291 if (change > 0) { |
279 // shrink gap | 292 // shrink gap |
280 gapStart += (change); | 293 gapStart += (change); |
281 for (int i = 0; i < text.length(); i++) { | 294 for (int i = 0; i < text.length; i++) { |
282 textStore[position + i]= text.charAt(i); | 295 textStore[position + i]= text[i]; |
283 } | 296 } |
284 } | 297 } |
285 | 298 |
286 // figure out the number of new lines that have been inserted | 299 // figure out the number of new lines that have been inserted |
287 int [][] newLines = indexLines(startLineOffset, startLineLength, 10); | 300 int [][] newLines = indexLines(startLineOffset, startLineLength, 10); |
288 // only insert an empty line if it is the last line in the text | 301 // only insert an empty line if it is the last line in the text |
289 int numNewLines = newLines.length - 1; | 302 int numNewLines = newLines.length - 1; |
290 if (newLines[numNewLines][1] is 0) { | 303 if (newLines[numNewLines][1] is 0) { |
291 // last inserted line is a new line | 304 // last inserted line is a new line |
292 if (endInsert) { | 305 if (endInsert) { |
293 // insert happening at end of the text, leave numNewLines as | 306 // insert happening at end of the text, leave numNewLines as |
294 // is since the last new line will not be concatenated with another | 307 // is since the last new line will not be concatenated with another |
295 // line | 308 // line |
296 numNewLines += 1; | 309 numNewLines += 1; |
297 } else { | 310 } else { |
298 numNewLines -= 1; | 311 numNewLines -= 1; |
299 } | 312 } |
300 } | 313 } |
301 | 314 |
302 // make room for the new lines | 315 // make room for the new lines |
303 expandLinesBy(numNewLines); | 316 expandLinesBy(numNewLines); |
304 // shift down the lines after the replace line | 317 // shift down the lines after the replace line |
305 for (int i = lineCount - 1; i > startLine; i--) { | 318 for (int i = lineCount_ - 1; i > startLine; i--) { |
306 lines[i + numNewLines]=lines[i]; | 319 lines[i + numNewLines]=lines[i]; |
307 } | 320 } |
308 // insert the new lines | 321 // insert the new lines |
309 for (int i = 0; i < numNewLines; i++) { | 322 for (int i = 0; i < numNewLines; i++) { |
310 newLines[i][0] += startLineOffset; | 323 newLines[i][0] += startLineOffset; |
313 // update the last inserted line | 326 // update the last inserted line |
314 if (numNewLines < newLines.length) { | 327 if (numNewLines < newLines.length) { |
315 newLines[numNewLines][0] += startLineOffset; | 328 newLines[numNewLines][0] += startLineOffset; |
316 lines[startLine + numNewLines] = newLines[numNewLines]; | 329 lines[startLine + numNewLines] = newLines[numNewLines]; |
317 } | 330 } |
318 | 331 |
319 lineCount += numNewLines; | 332 lineCount_ += numNewLines; |
320 gapLine = getLineAtPhysicalOffset(gapStart); | 333 gapLine = getLineAtPhysicalOffset(gapStart); |
321 } | 334 } |
322 /** | 335 /** |
323 * Moves the gap and adjusts its size in anticipation of a text change. | 336 * Moves the gap and adjusts its size in anticipation of a text change. |
324 * The gap is resized to actual size + the specified size and moved to the given | 337 * The gap is resized to actual size + the specified size and moved to the given |
325 * position. | 338 * position. |
326 * <p> | 339 * <p> |
327 * | 340 * |
328 * @param position the position at which a change is occurring | 341 * @param position the position at which a change is occurring |
329 * @param size the size of the change | 342 * @param size the size of the change |
341 // remove the old gap from the lines information | 354 // remove the old gap from the lines information |
342 if (gapExists()) { | 355 if (gapExists()) { |
343 // adjust the line length | 356 // adjust the line length |
344 lines[gapLine][1] = lines[gapLine][1] - oldSize; | 357 lines[gapLine][1] = lines[gapLine][1] - oldSize; |
345 // adjust the offsets of the lines after the gapLine | 358 // adjust the offsets of the lines after the gapLine |
346 for (int i = gapLine + 1; i < lineCount; i++) { | 359 for (int i = gapLine + 1; i < lineCount_; i++) { |
347 lines[i][0] = lines[i][0] - oldSize; | 360 lines[i][0] = lines[i][0] - oldSize; |
348 } | 361 } |
349 } | 362 } |
350 | 363 |
351 if (newSize < 0) { | 364 if (newSize < 0) { |
352 if (oldSize > 0) { | 365 if (oldSize > 0) { |
353 // removing the gap | 366 // removing the gap |
354 content = new char[textStore.length - oldSize]; | 367 content = new char[textStore.length - oldSize]; |
355 System.arraycopy(textStore, 0, content, 0, gapStart); | 368 System.arraycopy(textStore, 0, content, 0, gapStart); |
362 content = new char[textStore.length + (newSize - oldSize)]; | 375 content = new char[textStore.length + (newSize - oldSize)]; |
363 int newGapStart = position; | 376 int newGapStart = position; |
364 int newGapEnd = newGapStart + newSize; | 377 int newGapEnd = newGapStart + newSize; |
365 if (oldSize is 0) { | 378 if (oldSize is 0) { |
366 System.arraycopy(textStore, 0, content, 0, newGapStart); | 379 System.arraycopy(textStore, 0, content, 0, newGapStart); |
367 System.arraycopy(textStore, newGapStart, content, newGapEnd, content.length - newGapEnd); | 380 System.arraycopy(textStore, newGapStart, content, newGapEnd, content.length - newGapEnd); |
368 } else if (newGapStart < gapStart) { | 381 } else if (newGapStart < gapStart) { |
369 int delta = gapStart - newGapStart; | 382 int delta = gapStart - newGapStart; |
370 System.arraycopy(textStore, 0, content, 0, newGapStart); | 383 System.arraycopy(textStore, 0, content, 0, newGapStart); |
371 System.arraycopy(textStore, newGapStart, content, newGapEnd, delta); | 384 System.arraycopy(textStore, newGapStart, content, newGapEnd, delta); |
372 System.arraycopy(textStore, gapEnd, content, newGapEnd + delta, textStore.length - gapEnd); | 385 System.arraycopy(textStore, gapEnd, content, newGapEnd + delta, textStore.length - gapEnd); |
377 System.arraycopy(textStore, gapEnd + delta, content, newGapEnd, content.length - newGapEnd); | 390 System.arraycopy(textStore, gapEnd + delta, content, newGapEnd, content.length - newGapEnd); |
378 } | 391 } |
379 textStore = content; | 392 textStore = content; |
380 gapStart = newGapStart; | 393 gapStart = newGapStart; |
381 gapEnd = newGapEnd; | 394 gapEnd = newGapEnd; |
382 | 395 |
383 // add the new gap to the lines information | 396 // add the new gap to the lines information |
384 if (gapExists()) { | 397 if (gapExists()) { |
385 gapLine = newGapLine; | 398 gapLine = newGapLine; |
386 // adjust the line length | 399 // adjust the line length |
387 int gapLength = gapEnd - gapStart; | 400 int gapLength = gapEnd - gapStart; |
388 lines[gapLine][1] = lines[gapLine][1] + (gapLength); | 401 lines[gapLine][1] = lines[gapLine][1] + (gapLength); |
389 // adjust the offsets of the lines after the gapLine | 402 // adjust the offsets of the lines after the gapLine |
390 for (int i = gapLine + 1; i < lineCount; i++) { | 403 for (int i = gapLine + 1; i < lineCount_; i++) { |
391 lines[i][0] = lines[i][0] + gapLength; | 404 lines[i][0] = lines[i][0] + gapLength; |
392 } | 405 } |
393 } | 406 } |
394 } | 407 } |
395 /** | 408 /** |
396 * Returns the number of lines that are in the specified text. | 409 * Returns the number of lines that are in the specified text. |
397 * <p> | 410 * <p> |
398 * | 411 * |
399 * @param startOffset the start of the text to lineate | 412 * @param startOffset the start of the text to lineate |
400 * @param length the length of the text to lineate | 413 * @param length the length of the text to lineate |
402 */ | 415 */ |
403 int lineCount(int startOffset, int length){ | 416 int lineCount(int startOffset, int length){ |
404 if (length is 0) { | 417 if (length is 0) { |
405 return 0; | 418 return 0; |
406 } | 419 } |
407 int lineCount = 0; | 420 int lineCount_ = 0; |
408 int count = 0; | 421 int count = 0; |
409 int i = startOffset; | 422 int i = startOffset; |
410 if (i >= gapStart) { | 423 if (i >= gapStart) { |
411 i += gapEnd - gapStart; | 424 i += gapEnd - gapStart; |
412 } | 425 } |
413 while (count < length) { | 426 while (count < length) { |
414 if ((i >= gapStart) && (i < gapEnd)) { | 427 if ((i >= gapStart) && (i < gapEnd)) { |
415 // ignore the gap | 428 // ignore the gap |
416 } else { | 429 } else { |
417 char ch = textStore[i]; | 430 char ch = textStore[i]; |
418 if (ch is DWT.CR) { | 431 if (ch is DWT.CR) { |
419 // see if the next character is a LF | 432 // see if the next character is a LF |
420 if (i + 1 < textStore.length) { | 433 if (i + 1 < textStore.length) { |
421 ch = textStore[i+1]; | 434 ch = textStore[i+1]; |
422 if (ch is DWT.LF) { | 435 if (ch is DWT.LF) { |
423 i++; | 436 i++; |
424 count++; | 437 count++; |
425 } | 438 } |
426 } | 439 } |
427 lineCount++; | 440 lineCount_++; |
428 } else if (ch is DWT.LF) { | 441 } else if (ch is DWT.LF) { |
429 lineCount++; | 442 lineCount_++; |
430 } | 443 } |
431 count++; | 444 count++; |
432 } | 445 } |
433 i++; | 446 i++; |
434 } | 447 } |
435 return lineCount; | 448 return lineCount_; |
436 } | 449 } |
437 /** | 450 /** |
438 * Returns the number of lines that are in the specified text. | 451 * Returns the number of lines that are in the specified text. |
439 * <p> | 452 * <p> |
440 * | 453 * |
441 * @param text the text to lineate | 454 * @param text the text to lineate |
442 * @return number of lines in the text | 455 * @return number of lines in the text |
443 */ | 456 */ |
444 int lineCount(String text){ | 457 int lineCount(String text){ |
445 int lineCount = 0; | 458 int lineCount_ = 0; |
446 int length = text.length(); | 459 int length = text.length; |
447 for (int i = 0; i < length; i++) { | 460 for (int i = 0; i < length; i++) { |
448 char ch = text.charAt(i); | 461 char ch = text[i]; |
449 if (ch is DWT.CR) { | 462 if (ch is DWT.CR) { |
450 if (i + 1 < length && text.charAt(i + 1) is DWT.LF) { | 463 if (i + 1 < length && text[i + 1] is DWT.LF) { |
451 i++; | 464 i++; |
452 } | 465 } |
453 lineCount++; | 466 lineCount_++; |
454 } else if (ch is DWT.LF) { | 467 } else if (ch is DWT.LF) { |
455 lineCount++; | 468 lineCount_++; |
456 } | 469 } |
457 } | 470 } |
458 return lineCount; | 471 return lineCount_; |
459 } | 472 } |
460 /** | 473 /** |
461 * @return the logical length of the text store | 474 * @return the logical length of the text store |
462 */ | 475 */ |
463 public int getCharCount() { | 476 public int getCharCount() { |
473 * @exception IllegalArgumentException <ul> | 486 * @exception IllegalArgumentException <ul> |
474 * <li>ERROR_INVALID_ARGUMENT when index is out of range</li> | 487 * <li>ERROR_INVALID_ARGUMENT when index is out of range</li> |
475 * </ul> | 488 * </ul> |
476 */ | 489 */ |
477 public String getLine(int index) { | 490 public String getLine(int index) { |
478 if ((index >= lineCount) || (index < 0)) error(DWT.ERROR_INVALID_ARGUMENT); | 491 if ((index >= lineCount_) || (index < 0)) error(DWT.ERROR_INVALID_ARGUMENT); |
479 int start = lines[index][0]; | 492 int start = lines[index][0]; |
480 int length = lines[index][1]; | 493 int length_ = lines[index][1]; |
481 int end = start + length - 1; | 494 int end = start + length_ - 1; |
482 if (!gapExists() || (end < gapStart) || (start >= gapEnd)) { | 495 if (!gapExists() || (end < gapStart) || (start >= gapEnd)) { |
483 // line is before or after the gap | 496 // line is before or after the gap |
484 while ((length - 1 >= 0) && isDelimiter(textStore[start+length-1])) { | 497 while ((length_ - 1 >= 0) && isDelimiter(textStore[start+length_-1])) { |
485 length--; | 498 length_--; |
486 } | 499 } |
487 return new String(textStore, start, length); | 500 return textStore[ start .. start + length_].dup; |
488 } else { | 501 } else { |
489 // gap is in the specified range, strip out the gap | 502 // gap is in the specified range, strip out the gap |
490 StringBuffer buf = new StringBuffer(); | 503 StringBuffer buf = new StringBuffer(); |
491 int gapLength = gapEnd - gapStart; | 504 int gapLength = gapEnd - gapStart; |
492 buf.append(textStore, start, gapStart - start); | 505 buf.append(textStore[ start .. gapStart ] ); |
493 buf.append(textStore, gapEnd, length - gapLength - (gapStart - start)); | 506 buf.append(textStore[ gapEnd .. gapEnd + length_ - gapLength - (gapStart - start) ]); |
494 length = buf.length(); | 507 length_ = buf.length; |
495 while ((length - 1 >=0) && isDelimiter(buf.charAt(length - 1))) { | 508 while ((length_ - 1 >=0) && isDelimiter(buf.slice[length_ - 1])) { |
496 length--; | 509 length_--; |
497 } | 510 } |
498 return buf.toString().substring(0, length); | 511 return buf.toString()[ 0 .. length_ ].dup; |
499 } | 512 } |
500 } | 513 } |
501 /** | 514 /** |
502 * Returns the line delimiter that should be used by the StyledText | 515 * Returns the line delimiter that should be used by the StyledText |
503 * widget when inserting new lines. This delimiter may be different than the | 516 * widget when inserting new lines. This delimiter may be different than the |
504 * delimiter that is used by the <code>StyledTextContent</code> interface. | 517 * delimiter that is used by the <code>StyledTextContent</code> interface. |
505 * <p> | 518 * <p> |
506 * | 519 * |
507 * @return the platform line delimiter as specified in the line.separator | 520 * @return the platform line delimiter as specified in the line.separator |
516 * @param index the index of the line to return | 529 * @param index the index of the line to return |
517 * @return the logical line text (i.e., without the gap) with delimiters | 530 * @return the logical line text (i.e., without the gap) with delimiters |
518 */ | 531 */ |
519 String getFullLine(int index) { | 532 String getFullLine(int index) { |
520 int start = lines[index][0]; | 533 int start = lines[index][0]; |
521 int length = lines[index][1]; | 534 int length_ = lines[index][1]; |
522 int end = start + length - 1; | 535 int end = start + length_ - 1; |
523 if (!gapExists() || (end < gapStart) || (start >= gapEnd)) { | 536 if (!gapExists() || (end < gapStart) || (start >= gapEnd)) { |
524 // line is before or after the gap | 537 // line is before or after the gap |
525 return new String(textStore, start, length); | 538 return textStore[ start .. start + length_ ].dup; |
526 } else { | 539 } else { |
527 // gap is in the specified range, strip out the gap | 540 // gap is in the specified range, strip out the gap |
528 StringBuffer buffer = new StringBuffer(); | 541 StringBuffer buffer = new StringBuffer(); |
529 int gapLength = gapEnd - gapStart; | 542 int gapLength = gapEnd - gapStart; |
530 buffer.append(textStore, start, gapStart - start); | 543 buffer.append(textStore[ start .. gapStart ]); |
531 buffer.append(textStore, gapEnd, length - gapLength - (gapStart - start)); | 544 buffer.append(textStore[ gapEnd .. gapEnd + length_ - gapLength - (gapStart - start) ]); |
532 return buffer.toString(); | 545 return buffer.toString().dup; |
533 } | 546 } |
534 } | 547 } |
535 /** | 548 /** |
536 * Returns the physical line at the given index (i.e., with delimiters and the gap). | 549 * Returns the physical line at the given index (i.e., with delimiters and the gap). |
537 * <p> | 550 * <p> |
538 * | 551 * |
539 * @param index the line index | 552 * @param index the line index |
540 * @return the physical line | 553 * @return the physical line |
541 */ | 554 */ |
542 String getPhysicalLine(int index) { | 555 String getPhysicalLine(int index) { |
543 int start = lines[index][0]; | 556 int start = lines[index][0]; |
544 int length = lines[index][1]; | 557 int length_ = lines[index][1]; |
545 return getPhysicalText(start, length); | 558 return getPhysicalText(start, length_); |
546 } | 559 } |
547 /** | 560 /** |
548 * @return the number of lines in the text store | 561 * @return the number of lines in the text store |
549 */ | 562 */ |
550 public int getLineCount(){ | 563 public int getLineCount(){ |
551 return lineCount; | 564 return lineCount_; |
552 } | 565 } |
553 /** | 566 /** |
554 * Returns the line at the given offset. | 567 * Returns the line at the given offset. |
555 * <p> | 568 * <p> |
556 * | 569 * |
569 } else { | 582 } else { |
570 // position includes the gap | 583 // position includes the gap |
571 position = charPosition + (gapEnd - gapStart); | 584 position = charPosition + (gapEnd - gapStart); |
572 } | 585 } |
573 | 586 |
574 // if last line and the line is not empty you can ask for | 587 // if last line and the line is not empty you can ask for |
575 // a position that doesn't exist (the one to the right of the | 588 // a position that doesn't exist (the one to the right of the |
576 // last character) - for inserting | 589 // last character) - for inserting |
577 if (lineCount > 0) { | 590 if (lineCount_ > 0) { |
578 int lastLine = lineCount - 1; | 591 int lastLine = lineCount_ - 1; |
579 if (position is lines[lastLine][0] + lines[lastLine][1]) | 592 if (position is lines[lastLine][0] + lines[lastLine][1]) |
580 return lastLine; | 593 return lastLine; |
581 } | 594 } |
582 | 595 |
583 int high = lineCount; | 596 int high = lineCount_; |
584 int low = -1; | 597 int low = -1; |
585 int index = lineCount; | 598 int index = lineCount_; |
586 while (high - low > 1) { | 599 while (high - low > 1) { |
587 index = (high + low) / 2; | 600 index = (high + low) / 2; |
588 int lineStart = lines[index][0]; | 601 int lineStart = lines[index][0]; |
589 int lineEnd = lineStart + lines[index][1] - 1; | 602 int lineEnd = lineStart + lines[index][1] - 1; |
590 if (position <= lineStart) { | 603 if (position <= lineStart) { |
604 * | 617 * |
605 * @param position physical character offset (i.e., includes gap) | 618 * @param position physical character offset (i.e., includes gap) |
606 * @return the line index | 619 * @return the line index |
607 */ | 620 */ |
608 int getLineAtPhysicalOffset(int position){ | 621 int getLineAtPhysicalOffset(int position){ |
609 int high = lineCount; | 622 int high = lineCount_; |
610 int low = -1; | 623 int low = -1; |
611 int index = lineCount; | 624 int index = lineCount_; |
612 while (high - low > 1) { | 625 while (high - low > 1) { |
613 index = (high + low) / 2; | 626 index = (high + low) / 2; |
614 int lineStart = lines[index][0]; | 627 int lineStart = lines[index][0]; |
615 int lineEnd = lineStart + lines[index][1] - 1; | 628 int lineEnd = lineStart + lines[index][1] - 1; |
616 if (position <= lineStart) { | 629 if (position <= lineStart) { |
626 } | 639 } |
627 /** | 640 /** |
628 * Returns the logical offset of the given line. | 641 * Returns the logical offset of the given line. |
629 * <p> | 642 * <p> |
630 * | 643 * |
631 * @param lineIndex index of line | 644 * @param lineIndex index of line |
632 * @return the logical starting offset of the line. When there are not any lines, | 645 * @return the logical starting offset of the line. When there are not any lines, |
633 * getOffsetAtLine(0) is a valid call that should answer 0. | 646 * getOffsetAtLine(0) is a valid call that should answer 0. |
634 * @exception IllegalArgumentException <ul> | 647 * @exception IllegalArgumentException <ul> |
635 * <li>ERROR_INVALID_ARGUMENT when lineIndex is out of range</li> | 648 * <li>ERROR_INVALID_ARGUMENT when lineIndex is out of range</li> |
636 * </ul> | 649 * </ul> |
637 */ | 650 */ |
638 public int getOffsetAtLine(int lineIndex) { | 651 public int getOffsetAtLine(int lineIndex) { |
639 if (lineIndex is 0) return 0; | 652 if (lineIndex is 0) return 0; |
640 if ((lineIndex >= lineCount) || (lineIndex < 0)) error(DWT.ERROR_INVALID_ARGUMENT); | 653 if ((lineIndex >= lineCount_) || (lineIndex < 0)) error(DWT.ERROR_INVALID_ARGUMENT); |
641 int start = lines[lineIndex][0]; | 654 int start = lines[lineIndex][0]; |
642 if (start > gapEnd) { | 655 if (start > gapEnd) { |
643 return start - (gapEnd - gapStart); | 656 return start - (gapEnd - gapStart); |
644 } else { | 657 } else { |
645 return start; | 658 return start; |
646 } | 659 } |
647 } | 660 } |
648 /** | 661 /** |
649 * Increases the line indexes array to accommodate more lines. | 662 * Increases the line indexes array to accommodate more lines. |
650 * <p> | 663 * <p> |
651 * | 664 * |
652 * @param numLines the number to increase the array by | 665 * @param numLines the number to increase the array by |
653 */ | 666 */ |
654 void expandLinesBy(int numLines) { | 667 void expandLinesBy(int numLines) { |
655 int size = lines.length; | 668 int size = lines.length; |
656 if (size - lineCount >= numLines) { | 669 if (size - lineCount_ >= numLines) { |
657 return; | 670 return; |
658 } | 671 } |
659 int[][] newLines = new int[size+Math.max(10, numLines)][2]; | 672 int[][] newLines = new int[][]( size+Math.max(10, numLines), 2 ); |
660 System.arraycopy(lines, 0, newLines, 0, size); | 673 System.arraycopy(lines, 0, newLines, 0, size); |
661 lines = newLines; | 674 lines = newLines; |
662 } | 675 } |
663 /** | 676 /** |
664 * Reports an DWT error. | 677 * Reports an DWT error. |
665 * <p> | 678 * <p> |
666 * | 679 * |
667 * @param code the error code | 680 * @param code the error code |
668 */ | 681 */ |
669 void error (int code) { | 682 void error (int code) { |
670 DWT.error(code); | 683 DWT.error(code); |
671 } | 684 } |
672 /** | 685 /** |
673 * Returns whether or not a gap exists in the text store. | 686 * Returns whether or not a gap exists in the text store. |
674 * <p> | 687 * <p> |
675 * | 688 * |
676 * @return true if gap exists, false otherwise | 689 * @return true if gap exists, false otherwise |
677 */ | 690 */ |
678 bool gapExists() { | 691 bool gapExists() { |
679 return gapStart !is gapEnd; | 692 return gapStart !is gapEnd; |
680 } | 693 } |
681 /** | 694 /** |
682 * Returns a String representing the continuous content of | 695 * Returns a string representing the continuous content of |
683 * the text store. | 696 * the text store. |
684 * <p> | 697 * <p> |
685 * | 698 * |
686 * @param start the physical start offset of the text to return | 699 * @param start the physical start offset of the text to return |
687 * @param length the physical length of the text to return | 700 * @param length the physical length of the text to return |
688 * @return the text | 701 * @return the text |
689 */ | 702 */ |
690 String getPhysicalText(int start, int length) { | 703 String getPhysicalText(int start, int length_) { |
691 return new String(textStore, start, length); | 704 return textStore[ start .. start + length_ ].dup; |
692 } | 705 } |
693 /** | 706 /** |
694 * Returns a String representing the logical content of | 707 * Returns a string representing the logical content of |
695 * the text store (i.e., gap stripped out). | 708 * the text store (i.e., gap stripped out). |
696 * <p> | 709 * <p> |
697 * | 710 * |
698 * @param start the logical start offset of the text to return | 711 * @param start the logical start offset of the text to return |
699 * @param length the logical length of the text to return | 712 * @param length the logical length of the text to return |
700 * @return the text | 713 * @return the text |
701 */ | 714 */ |
702 public String getTextRange(int start, int length) { | 715 public String getTextRange(int start, int length_) { |
703 if (textStore is null) | 716 if (textStore is null) |
704 return ""; | 717 return ""; |
705 if (length is 0) | 718 if (length_ is 0) |
706 return ""; | 719 return ""; |
707 int end= start + length; | 720 int end= start + length_; |
708 if (!gapExists() || (end < gapStart)) | 721 if (!gapExists() || (end < gapStart)) |
709 return new String(textStore, start, length); | 722 return textStore[ start .. start + length_].dup; |
710 if (gapStart < start) { | 723 if (gapStart < start) { |
711 int gapLength= gapEnd - gapStart; | 724 int gapLength= gapEnd - gapStart; |
712 return new String(textStore, start + gapLength , length); | 725 return textStore[ start + gapLength .. start + gapLength + length_ ].dup; |
713 } | 726 } |
714 StringBuffer buf = new StringBuffer(); | 727 StringBuffer buf = new StringBuffer(); |
715 buf.append(textStore, start, gapStart - start); | 728 buf.append(textStore[ start .. start + gapStart - start ] ); |
716 buf.append(textStore, gapEnd, end - gapStart); | 729 buf.append(textStore[ gapEnd .. gapEnd + end - gapStart ] ); |
717 return buf.toString(); | 730 return buf.toString().dup; |
718 } | 731 } |
719 /** | 732 /** |
720 * Removes the specified <code>TextChangeListener</code>. | 733 * Removes the specified <code>TextChangeListener</code>. |
721 * <p> | 734 * <p> |
722 * | 735 * |
723 * @param listener the listener | 736 * @param listener the listener which should no longer be notified |
737 * | |
724 * @exception IllegalArgumentException <ul> | 738 * @exception IllegalArgumentException <ul> |
725 * <li>ERROR_NULL_ARGUMENT when listener is null</li> | 739 * <li>ERROR_NULL_ARGUMENT when listener is null</li> |
726 * </ul> | 740 * </ul> |
727 */ | 741 */ |
728 public void removeTextChangeListener(TextChangeListener listener){ | 742 public void removeTextChangeListener(TextChangeListener listener){ |
729 if (listener is null) error(DWT.ERROR_NULL_ARGUMENT); | 743 if (listener is null) error(DWT.ERROR_NULL_ARGUMENT); |
730 for (int i = 0; i < textListeners.size(); i++) { | 744 for (int i = 0; i < textListeners.length; i++) { |
731 TypedListener typedListener = cast(TypedListener) textListeners.elementAt(i); | 745 TypedListener typedListener = cast(TypedListener) textListeners[i]; |
732 if (typedListener.getEventListener () is listener) { | 746 if (typedListener.getEventListener () is listener) { |
733 textListeners.removeElementAt(i); | 747 textListeners = textListeners[ 0 .. i ] ~ textListeners[ i+1 .. $ ]; |
734 break; | 748 break; |
735 } | 749 } |
736 } | 750 } |
737 } | 751 } |
738 /** | 752 /** |
739 * Replaces the text with <code>newText</code> starting at position <code>start</code> | 753 * Replaces the text with <code>newText</code> starting at position <code>start</code> |
740 * for a length of <code>replaceLength</code>. Notifies the appropriate listeners. | 754 * for a length of <code>replaceLength</code>. Notifies the appropriate listeners. |
741 * <p> | 755 * <p> |
742 * | 756 * |
743 * When sending the TextChangingEvent, <code>newLineCount</code> is the number of | 757 * When sending the TextChangingEvent, <code>newLineCount</code> is the number of |
744 * lines that are going to be inserted and <code>replaceLineCount</code> is | 758 * lines that are going to be inserted and <code>replaceLineCount</code> is |
745 * the number of lines that are going to be deleted, based on the change | 759 * the number of lines that are going to be deleted, based on the change |
746 * that occurs visually. For example: | 760 * that occurs visually. For example: |
747 * <ul> | 761 * <ul> |
748 * <li>(replaceText,newText) ==> (replaceLineCount,newLineCount) | 762 * <li>(replaceText,newText) is> (replaceLineCount,newLineCount) |
749 * <li>("","\n") ==> (0,1) | 763 * <li>("","\n") is> (0,1) |
750 * <li>("\n\n","a") ==> (2,0) | 764 * <li>("\n\n","a") is> (2,0) |
751 * </ul> | 765 * </ul> |
752 * </p> | 766 * </p> |
753 * | 767 * |
754 * @param start start offset of text to replace | 768 * @param start start offset of text to replace |
755 * @param replaceLength start offset of text to replace | 769 * @param replaceLength start offset of text to replace |
756 * @param newText start offset of text to replace | 770 * @param newText start offset of text to replace |
757 * | 771 * |
758 * @exception DWTException <ul> | 772 * @exception DWTException <ul> |
759 * <li>ERROR_INVALID_ARGUMENT when the text change results in a multi byte | 773 * <li>ERROR_INVALID_ARGUMENT when the text change results in a multi byte |
760 * line delimiter being split or partially deleted. Splitting a line | 774 * line delimiter being split or partially deleted. Splitting a line |
761 * delimiter by inserting text between the CR and LF characters of the | 775 * delimiter by inserting text between the CR and LF characters of the |
762 * \r\n delimiter or deleting part of this line delimiter is not supported</li> | 776 * \r\n delimiter or deleting part of this line delimiter is not supported</li> |
763 * </ul> | 777 * </ul> |
764 */ | 778 */ |
765 public void replaceTextRange(int start, int replaceLength, String newText){ | 779 public void replaceTextRange(int start, int replaceLength, String newText){ |
766 // check for invalid replace operations | 780 // check for invalid replace operations |
767 if (!isValidReplace(start, replaceLength, newText)) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | 781 if (!isValidReplace(start, replaceLength, newText)) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
768 | 782 |
769 // inform listeners | 783 // inform listeners |
770 StyledTextEvent event = new StyledTextEvent(this); | 784 StyledTextEvent event = new StyledTextEvent(this); |
771 event.type = StyledText.TextChanging; | 785 event.type = StyledText.TextChanging; |
772 event.start = start; | 786 event.start = start; |
773 event.replaceLineCount = lineCount(start, replaceLength); | 787 event.replaceLineCount = lineCount(start, replaceLength); |
774 event.text = newText; | 788 event.text = newText; |
775 event.newLineCount = lineCount(newText); | 789 event.newLineCount = lineCount(newText); |
776 event.replaceCharCount = replaceLength; | 790 event.replaceCharCount = replaceLength; |
777 event.newCharCount = newText.length(); | 791 event.newCharCount = newText.length; |
778 sendTextEvent(event); | 792 sendTextEvent(event); |
779 | 793 |
780 // first delete the text to be replaced | 794 // first delete the text to be replaced |
781 delete(start, replaceLength, event.replaceLineCount + 1); | 795 delete_(start, replaceLength, event.replaceLineCount + 1); |
782 // then insert the new text | 796 // then insert the new text |
783 insert(start, newText); | 797 insert(start, newText); |
784 // inform listeners | 798 // inform listeners |
785 event = new StyledTextEvent(this); | 799 event = new StyledTextEvent(this); |
786 event.type = StyledText.TextChanged; | 800 event.type = StyledText.TextChanged; |
788 } | 802 } |
789 /** | 803 /** |
790 * Sends the text listeners the TextChanged event. | 804 * Sends the text listeners the TextChanged event. |
791 */ | 805 */ |
792 void sendTextEvent(StyledTextEvent event) { | 806 void sendTextEvent(StyledTextEvent event) { |
793 for (int i = 0; i < textListeners.size(); i++) { | 807 for (int i = 0; i < textListeners.length; i++) { |
794 (cast(StyledTextListener)textListeners.elementAt(i)).handleEvent(event); | 808 (cast(StyledTextListener)textListeners[i]).handleEvent(event); |
795 } | 809 } |
796 } | 810 } |
797 /** | 811 /** |
798 * Sets the content to text and removes the gap since there are no sensible predictions | 812 * Sets the content to text and removes the gap since there are no sensible predictions |
799 * about where the next change will occur. | 813 * about where the next change will occur. |
800 * <p> | 814 * <p> |
801 * | 815 * |
802 * @param text the text | 816 * @param text the text |
803 */ | 817 */ |
804 public void setText (String text){ | 818 public void setText (String text){ |
805 textStore = text.toCharArray(); | 819 textStore = text.dup; |
806 gapStart = -1; | 820 gapStart = -1; |
807 gapEnd = -1; | 821 gapEnd = -1; |
808 expandExp = 1; | 822 expandExp = 1; |
809 indexLines(); | 823 indexLines(); |
810 StyledTextEvent event = new StyledTextEvent(this); | 824 StyledTextEvent event = new StyledTextEvent(this); |
817 * <p> | 831 * <p> |
818 * @param position the position at which the text to delete starts | 832 * @param position the position at which the text to delete starts |
819 * @param length the length of the text to delete | 833 * @param length the length of the text to delete |
820 * @param numLines the number of lines that are being deleted | 834 * @param numLines the number of lines that are being deleted |
821 */ | 835 */ |
822 void delete(int position, int length, int numLines) { | 836 void delete_(int position, int length_, int numLines) { |
823 if (length is 0) return; | 837 if (length_ is 0) return; |
824 | 838 |
825 int startLine = getLineAtOffset(position); | 839 int startLine = getLineAtOffset(position); |
826 int startLineOffset = getOffsetAtLine(startLine); | 840 int startLineOffset = getOffsetAtLine(startLine); |
827 int endLine = getLineAtOffset(position + length); | 841 int endLine = getLineAtOffset(position + length_); |
828 | 842 |
829 String endText = ""; | 843 String endText = ""; |
830 bool splittingDelimiter = false; | 844 bool splittingDelimiter = false; |
831 if (position + length < getCharCount()) { | 845 if (position + length_ < getCharCount()) { |
832 endText = getTextRange(position + length - 1, 2); | 846 endText = getTextRange(position + length_ - 1, 2); |
833 if ((endText.charAt(0) is DWT.CR) && (endText.charAt(1) is DWT.LF)) { | 847 if ((endText[0] is DWT.CR) && (endText[1] is DWT.LF)) { |
834 splittingDelimiter = true; | 848 splittingDelimiter = true; |
835 } | 849 } |
836 } | 850 } |
837 | 851 |
838 adjustGap(position + length, -length, startLine); | 852 adjustGap(position + length_, -length_, startLine); |
839 int [][] oldLines = indexLines(position, length + (gapEnd - gapStart), numLines); | 853 int [][] oldLines = indexLines(position, length_ + (gapEnd - gapStart), numLines); |
840 | 854 |
841 // enlarge the gap - the gap can be enlarged either to the | 855 // enlarge the gap - the gap can be enlarged either to the |
842 // right or left | 856 // right or left |
843 if (position + length is gapStart) { | 857 if (position + length_ is gapStart) { |
844 gapStart -= length; | 858 gapStart -= length_; |
845 } else { | 859 } else { |
846 gapEnd += length; | 860 gapEnd += length_; |
847 } | 861 } |
848 | 862 |
849 // figure out the length of the new concatenated line, do so by | 863 // figure out the length of the new concatenated line, do so by |
850 // finding the first line delimiter after position | 864 // finding the first line delimiter after position |
851 int j = position; | 865 int j = position; |
852 bool eol = false; | 866 bool eol = false; |
858 if (ch is DWT.CR && (textStore[j+1] is DWT.LF)) { | 872 if (ch is DWT.CR && (textStore[j+1] is DWT.LF)) { |
859 j++; | 873 j++; |
860 } | 874 } |
861 } | 875 } |
862 eol = true; | 876 eol = true; |
863 } | 877 } |
864 } | 878 } |
865 j++; | 879 j++; |
866 } | 880 } |
867 // update the line where the deletion started | 881 // update the line where the deletion started |
868 lines[startLine][1] = (position - startLineOffset) + (j - position); | 882 lines[startLine][1] = (position - startLineOffset) + (j - position); |
869 // figure out the number of lines that have been deleted | 883 // figure out the number of lines that have been deleted |
870 int numOldLines = oldLines.length - 1; | 884 int numOldLines = oldLines.length - 1; |
871 if (splittingDelimiter) numOldLines -= 1; | 885 if (splittingDelimiter) numOldLines -= 1; |
872 // shift up the lines after the last deleted line, no need to update | 886 // shift up the lines after the last deleted line, no need to update |
873 // the offset or length of the lines | 887 // the offset or length of the lines |
874 for (int i = endLine + 1; i < lineCount; i++) { | 888 for (int i = endLine + 1; i < lineCount_; i++) { |
875 lines[i - numOldLines] = lines[i]; | 889 lines[i - numOldLines] = lines[i]; |
876 } | 890 } |
877 lineCount -= numOldLines; | 891 lineCount_ -= numOldLines; |
878 gapLine = getLineAtPhysicalOffset(gapStart); | 892 gapLine = getLineAtPhysicalOffset(gapStart); |
879 } | 893 } |
880 } | 894 |
895 /++ | |
896 + DWT extension | |
897 +/ | |
898 int utf8AdjustOffset( int offset ){ | |
899 if (textStore is null) | |
900 return offset; | |
901 if (offset is 0) | |
902 return offset; | |
903 if( offset >= textStore.length ){ | |
904 return offset; | |
905 } | |
906 if (!gapExists() || (offset < gapStart)){ | |
907 while( textStore[offset] & 0xC0 is 0x80 ){ | |
908 offset--; | |
909 } | |
910 return offset; | |
911 } | |
912 int gapLength= gapEnd - gapStart; | |
913 if( offset+gapLength >= textStore.length ){ | |
914 return offset; | |
915 } | |
916 while( textStore[offset+gapLength] & 0xC0 is 0x80 ){ | |
917 offset--; | |
918 } | |
919 return offset; | |
920 } | |
921 | |
922 | |
923 } |