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 }