KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > custom > DefaultContent


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

11 package org.eclipse.swt.custom;
12
13 import org.eclipse.swt.*;
14 import org.eclipse.swt.internal.Compatibility;
15 import org.eclipse.swt.widgets.*;
16 import java.util.Vector JavaDoc;
17
18 class DefaultContent implements StyledTextContent {
19     private final static String JavaDoc LineDelimiter = System.getProperty("line.separator");
20
21     Vector JavaDoc textListeners = new Vector JavaDoc(); // stores text listeners for event sending
22
char[] textStore = new char[0]; // stores the actual text
23
int gapStart = -1; // the character position start of the gap
24
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
26
int highWatermark = 300;
27     int lowWatermark = 50;
28     
29     int[][] lines = new int[50][2]; // array of character positions and lengths representing the lines of text
30
int lineCount = 0; // the number of lines of text
31
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
33

34 /**
35  * Creates a new DefaultContent and initializes it. A <code>StyledTextContent</> will always have
36  * at least one empty line.
37  */

38 DefaultContent() {
39     super();
40     setText("");
41 }
42 /**
43  * 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.
45  * <p>
46  *
47  * @param start the start of the line
48  * @param length the length of the line
49  */

50 void addLineIndex(int start, int length) {
51     int size = lines.length;
52     if (lineCount == size) {
53         // expand the lines by powers of 2
54
int[][] newLines = new int[size+Compatibility.pow2(expandExp)][2];
55         System.arraycopy(lines, 0, newLines, 0, size);
56         lines = newLines;
57         expandExp++;
58     }
59     int[] range = new int[] {start, length};
60     lines[lineCount] = range;
61     lineCount++;
62 }
63 /**
64  * 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.
66  * <p>
67  *
68  * @param start the start of the line
69  * @param length the length of the line
70  * @param linesArray the array to which to add the line index
71  * @param count the position at which to add the line
72  * @return a new array of line indexes
73  */

74 int[][] addLineIndex(int start, int length, int[][] linesArray, int count) {
75     int size = linesArray.length;
76     int[][] newLines = linesArray;
77     if (count == size) {
78         newLines = new int[size+Compatibility.pow2(replaceExpandExp)][2];
79         replaceExpandExp++;
80         System.arraycopy(linesArray, 0, newLines, 0, size);
81     }
82     int[] range = new int[] {start, length};
83     newLines[count] = range;
84     return newLines;
85 }
86 /**
87  * Adds a <code>TextChangeListener</code> listening for
88  * <code>TextChangingEvent</code> and <code>TextChangedEvent</code>. A
89  * <code>TextChangingEvent</code> is sent before changes to the text occur.
90  * A <code>TextChangedEvent</code> is sent after changes to the text
91  * occurred.
92  * <p>
93  *
94  * @param listener the listener
95  * @exception IllegalArgumentException <ul>
96  * <li>ERROR_NULL_ARGUMENT when listener is null</li>
97  * </ul>
98  */

99 public void addTextChangeListener(TextChangeListener listener) {
100     if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
101     StyledTextListener typedListener = new StyledTextListener(listener);
102     textListeners.addElement(typedListener);
103 }
104 /**
105  * Adjusts the gap to accommodate a text change that is occurring.
106  * <p>
107  *
108  * @param position the position at which a change is occurring
109  * @param sizeHint the size of the change
110  * @param line the line where the gap will go
111  */

112 void adjustGap(int position, int sizeHint, int line) {
113     if (position == gapStart) {
114         // text is being inserted at the gap position
115
int size = (gapEnd - gapStart) - sizeHint;
116         if (lowWatermark <= size && size <= highWatermark)
117             return;
118     } else if ((position + sizeHint == gapStart) && (sizeHint < 0)) {
119         // text is being deleted at the gap position
120
int size = (gapEnd - gapStart) - sizeHint;
121         if (lowWatermark <= size && size <= highWatermark)
122             return;
123     }
124     moveAndResizeGap(position, sizeHint, line);
125 }
126 /**
127  * Calculates the indexes of each line in the text store. Assumes no gap exists.
128  * Optimized to do less checking.
129  */

130 void indexLines(){
131     int start = 0;
132     lineCount = 0;
133     int textLength = textStore.length;
134     int i;
135     for (i = start; i < textLength; i++) {
136         char ch = textStore[i];
137         if (ch == SWT.CR) {
138             // see if the next character is a LF
139
if (i + 1 < textLength) {
140                 ch = textStore[i+1];
141                 if (ch == SWT.LF) {
142                     i++;
143                 }
144             }
145             addLineIndex(start, i - start + 1);
146             start = i + 1;
147         } else if (ch == SWT.LF) {
148             addLineIndex(start, i - start + 1);
149             start = i + 1;
150         }
151     }
152     addLineIndex(start, i - start);
153 }
154 /**
155  * Returns whether or not the given character is a line delimiter. Both CR and LF
156  * are valid line delimiters.
157  * <p>
158  *
159  * @param ch the character to test
160  * @return true if ch is a delimiter, false otherwise
161  */

162 boolean isDelimiter(char ch) {
163     if (ch == SWT.CR) return true;
164     if (ch == SWT.LF) return true;
165     return false;
166 }
167 /**
168  * 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.
170  * <p>
171  *
172  * @param start start offset of text to replace
173  * @param replaceLength start offset of text to replace
174  * @param newText start offset of text to replace
175  * @return a boolean specifying whether or not the replace operation is valid
176  */

177 protected boolean isValidReplace(int start, int replaceLength, String JavaDoc newText){
178     if (replaceLength == 0) {
179         // inserting text, see if the \r\n line delimiter is being split
180
if (start == 0) return true;
181         if (start == getCharCount()) return true;
182         char before = getTextRange(start - 1, 1).charAt(0);
183         if (before == '\r') {
184             char after = getTextRange(start, 1).charAt(0);
185             if (after == '\n') return false;
186         }
187     } else {
188         // deleting text, see if part of a \r\n line delimiter is being deleted
189
char startChar = getTextRange(start, 1).charAt(0);
190         if (startChar == '\n') {
191             // see if char before delete position is \r
192
if (start != 0) {
193                 char before = getTextRange(start - 1, 1).charAt(0);
194                 if (before == '\r') return false;
195             }
196         }
197         char endChar = getTextRange(start + replaceLength - 1, 1).charAt(0);
198         if (endChar == '\r') {
199             // see if char after delete position is \n
200
if (start + replaceLength != getCharCount()) {
201                 char after = getTextRange(start + replaceLength, 1).charAt(0);
202                 if (after == '\n') return false;
203             }
204         }
205     }
206     return true;
207 }
208 /**
209  * Calculates the indexes of each line of text in the given range.
210  * <p>
211  *
212  * @param offset the logical start offset of the text lineate
213  * @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,
215  * 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
217  * a length
218  */

219 int[][] indexLines(int offset, int length, int numLines){
220     int[][] indexedLines = new int[numLines][2];
221     int start = 0;
222     int lineCount = 0;
223     int i;
224     replaceExpandExp = 1;
225     for (i = start; i < length; i++) {
226         int location = i + offset;
227         if ((location >= gapStart) && (location < gapEnd)) {
228             // ignore the gap
229
} else {
230             char ch = textStore[location];
231             if (ch == SWT.CR) {
232                 // see if the next character is a LF
233
if (location+1 < textStore.length) {
234                     ch = textStore[location+1];
235                     if (ch == SWT.LF) {
236                         i++;
237                     }
238                 }
239                 indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount);
240                 lineCount++;
241                 start = i + 1;
242             } else if (ch == SWT.LF) {
243                 indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount);
244                 lineCount++;
245                 start = i + 1;
246             }
247         }
248     }
249     int[][] newLines = new int[lineCount+1][2];
250     System.arraycopy(indexedLines, 0, newLines, 0, lineCount);
251     int[] range = new int[] {start, i - start};
252     newLines[lineCount] = range;
253     return newLines;
254 }
255 /**
256  * Inserts text.
257  * <p>
258  *
259  * @param position the position at which to insert the text
260  * @param text the text to insert
261  */

262 void insert(int position, String JavaDoc text) {
263     if (text.length() == 0) return;
264                 
265     int startLine = getLineAtOffset(position);
266     int change = text.length();
267     boolean endInsert = position == getCharCount();
268     adjustGap(position, change, startLine);
269
270     // during an insert the gap will be adjusted to start at
271
// position and it will be associated with startline, the
272
// inserted text will be placed in the gap
273
int startLineOffset = getOffsetAtLine(startLine);
274     // at this point, startLineLength will include the start line
275
// and all of the newly inserted text
276
int startLineLength = getPhysicalLine(startLine).length();
277     
278     if (change > 0) {
279         // shrink gap
280
gapStart += (change);
281         for (int i = 0; i < text.length(); i++) {
282             textStore[position + i]= text.charAt(i);
283         }
284     }
285         
286     // figure out the number of new lines that have been inserted
287
int [][] newLines = indexLines(startLineOffset, startLineLength, 10);
288     // only insert an empty line if it is the last line in the text
289
int numNewLines = newLines.length - 1;
290     if (newLines[numNewLines][1] == 0) {
291         // last inserted line is a new line
292
if (endInsert) {
293             // insert happening at end of the text, leave numNewLines as
294
// is since the last new line will not be concatenated with another
295
// line
296
numNewLines += 1;
297         } else {
298             numNewLines -= 1;
299         }
300     }
301     
302     // make room for the new lines
303
expandLinesBy(numNewLines);
304     // shift down the lines after the replace line
305
for (int i = lineCount - 1; i > startLine; i--) {
306         lines[i + numNewLines]=lines[i];
307     }
308     // insert the new lines
309
for (int i = 0; i < numNewLines; i++) {
310         newLines[i][0] += startLineOffset;
311         lines[startLine + i]=newLines[i];
312     }
313     // update the last inserted line
314
if (numNewLines < newLines.length) {
315         newLines[numNewLines][0] += startLineOffset;
316         lines[startLine + numNewLines] = newLines[numNewLines];
317     }
318     
319     lineCount += numNewLines;
320     gapLine = getLineAtPhysicalOffset(gapStart);
321 }
322 /**
323  * 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
325  * position.
326  * <p>
327  *
328  * @param position the position at which a change is occurring
329  * @param size the size of the change
330  * @param newGapLine the line where the gap should be put
331  */

332 void moveAndResizeGap(int position, int size, int newGapLine) {
333     char[] content = null;
334     int oldSize = gapEnd - gapStart;
335     int newSize;
336     if (size > 0) {
337         newSize = highWatermark + size;
338     } else {
339         newSize = lowWatermark - size;
340     }
341     // remove the old gap from the lines information
342
if (gapExists()) {
343         // adjust the line length
344
lines[gapLine][1] = lines[gapLine][1] - oldSize;
345         // adjust the offsets of the lines after the gapLine
346
for (int i = gapLine + 1; i < lineCount; i++) {
347             lines[i][0] = lines[i][0] - oldSize;
348         }
349     }
350     
351     if (newSize < 0) {
352         if (oldSize > 0) {
353             // removing the gap
354
content = new char[textStore.length - oldSize];
355             System.arraycopy(textStore, 0, content, 0, gapStart);
356             System.arraycopy(textStore, gapEnd, content, gapStart, content.length - gapStart);
357             textStore = content;
358         }
359         gapStart = gapEnd = position;
360         return;
361     }
362     content = new char[textStore.length + (newSize - oldSize)];
363     int newGapStart = position;
364     int newGapEnd = newGapStart + newSize;
365     if (oldSize == 0) {
366         System.arraycopy(textStore, 0, content, 0, newGapStart);
367         System.arraycopy(textStore, newGapStart, content, newGapEnd, content.length - newGapEnd);
368     } else if (newGapStart < gapStart) {
369         int delta = gapStart - newGapStart;
370         System.arraycopy(textStore, 0, content, 0, newGapStart);
371         System.arraycopy(textStore, newGapStart, content, newGapEnd, delta);
372         System.arraycopy(textStore, gapEnd, content, newGapEnd + delta, textStore.length - gapEnd);
373     } else {
374         int delta = newGapStart - gapStart;
375         System.arraycopy(textStore, 0, content, 0, gapStart);
376         System.arraycopy(textStore, gapEnd, content, gapStart, delta);
377         System.arraycopy(textStore, gapEnd + delta, content, newGapEnd, content.length - newGapEnd);
378     }
379     textStore = content;
380     gapStart = newGapStart;
381     gapEnd = newGapEnd;
382     
383     // add the new gap to the lines information
384
if (gapExists()) {
385         gapLine = newGapLine;
386         // adjust the line length
387
int gapLength = gapEnd - gapStart;
388         lines[gapLine][1] = lines[gapLine][1] + (gapLength);
389         // adjust the offsets of the lines after the gapLine
390
for (int i = gapLine + 1; i < lineCount; i++) {
391             lines[i][0] = lines[i][0] + gapLength;
392         }
393     }
394 }
395 /**
396  * Returns the number of lines that are in the specified text.
397  * <p>
398  *
399  * @param startOffset the start of the text to lineate
400  * @param length the length of the text to lineate
401  * @return number of lines
402  */

403 int lineCount(int startOffset, int length){
404     if (length == 0) {
405         return 0;
406     }
407     int lineCount = 0;
408     int count = 0;
409     int i = startOffset;
410     if (i >= gapStart) {
411         i += gapEnd - gapStart;
412     }
413     while (count < length) {
414         if ((i >= gapStart) && (i < gapEnd)) {
415             // ignore the gap
416
} else {
417             char ch = textStore[i];
418             if (ch == SWT.CR) {
419                 // see if the next character is a LF
420
if (i + 1 < textStore.length) {
421                     ch = textStore[i+1];
422                     if (ch == SWT.LF) {
423                         i++;
424                         count++;
425                     }
426                 }
427                 lineCount++;
428             } else if (ch == SWT.LF) {
429                 lineCount++;
430             }
431             count++;
432         }
433         i++;
434     }
435     return lineCount;
436 }
437 /**
438  * Returns the number of lines that are in the specified text.
439  * <p>
440  *
441  * @param text the text to lineate
442  * @return number of lines in the text
443  */

444 int lineCount(String JavaDoc text){
445     int lineCount = 0;
446     int length = text.length();
447     for (int i = 0; i < length; i++) {
448         char ch = text.charAt(i);
449         if (ch == SWT.CR) {
450             if (i + 1 < length && text.charAt(i + 1) == SWT.LF) {
451                 i++;
452             }
453             lineCount++;
454         } else if (ch == SWT.LF) {
455             lineCount++;
456         }
457     }
458     return lineCount;
459 }
460 /**
461  * @return the logical length of the text store
462  */

463 public int getCharCount() {
464     int length = gapEnd - gapStart;
465     return (textStore.length - length);
466 }
467 /**
468  * Returns the line at <code>index</code> without delimiters.
469  * <p>
470  *
471  * @param index the index of the line to return
472  * @return the logical line text (i.e., without the gap)
473  * @exception IllegalArgumentException <ul>
474  * <li>ERROR_INVALID_ARGUMENT when index is out of range</li>
475  * </ul>
476  */

477 public String JavaDoc getLine(int index) {
478     if ((index >= lineCount) || (index < 0)) error(SWT.ERROR_INVALID_ARGUMENT);
479     int start = lines[index][0];
480     int length = lines[index][1];
481     int end = start + length - 1;
482     if (!gapExists() || (end < gapStart) || (start >= gapEnd)) {
483         // line is before or after the gap
484
while ((length - 1 >= 0) && isDelimiter(textStore[start+length-1])) {
485             length--;
486         }
487         return new String JavaDoc(textStore, start, length);
488     } else {
489         // gap is in the specified range, strip out the gap
490
StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
491         int gapLength = gapEnd - gapStart;
492         buf.append(textStore, start, gapStart - start);
493         buf.append(textStore, gapEnd, length - gapLength - (gapStart - start));
494         length = buf.length();
495         while ((length - 1 >=0) && isDelimiter(buf.charAt(length - 1))) {
496             length--;
497         }
498         return buf.toString().substring(0, length);
499     }
500 }
501 /**
502  * Returns the line delimiter that should be used by the StyledText
503  * widget when inserting new lines. This delimiter may be different than the
504  * delimiter that is used by the <code>StyledTextContent</code> interface.
505  * <p>
506  *
507  * @return the platform line delimiter as specified in the line.separator
508  * system property.
509  */

510 public String JavaDoc getLineDelimiter() {
511     return LineDelimiter;
512 }
513 /**
514  * Returns the line at the given index with delimiters.
515  * <p>
516  * @param index the index of the line to return
517  * @return the logical line text (i.e., without the gap) with delimiters
518  */

519 String JavaDoc getFullLine(int index) {
520     int start = lines[index][0];
521     int length = lines[index][1];
522     int end = start + length - 1;
523     if (!gapExists() || (end < gapStart) || (start >= gapEnd)) {
524         // line is before or after the gap
525
return new String JavaDoc(textStore, start, length);
526     } else {
527         // gap is in the specified range, strip out the gap
528
StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
529         int gapLength = gapEnd - gapStart;
530         buffer.append(textStore, start, gapStart - start);
531         buffer.append(textStore, gapEnd, length - gapLength - (gapStart - start));
532         return buffer.toString();
533     }
534 }
535 /**
536  * Returns the physical line at the given index (i.e., with delimiters and the gap).
537  * <p>
538  *
539  * @param index the line index
540  * @return the physical line
541  */

542 String JavaDoc getPhysicalLine(int index) {
543     int start = lines[index][0];
544     int length = lines[index][1];
545     return getPhysicalText(start, length);
546 }
547 /**
548  * @return the number of lines in the text store
549  */

550 public int getLineCount(){
551     return lineCount;
552 }
553 /**
554  * Returns the line at the given offset.
555  * <p>
556  *
557  * @param charPosition logical character offset (i.e., does not include gap)
558  * @return the line index
559  * @exception IllegalArgumentException <ul>
560  * <li>ERROR_INVALID_ARGUMENT when charPosition is out of range</li>
561  * </ul>
562  */

563 public int getLineAtOffset(int charPosition){
564     if ((charPosition > getCharCount()) || (charPosition < 0)) error(SWT.ERROR_INVALID_ARGUMENT);
565     int position;
566     if (charPosition < gapStart) {
567         // position is before the gap
568
position = charPosition;
569     } else {
570         // position includes the gap
571
position = charPosition + (gapEnd - gapStart);
572     }
573
574     // 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
576
// last character) - for inserting
577
if (lineCount > 0) {
578         int lastLine = lineCount - 1;
579         if (position == lines[lastLine][0] + lines[lastLine][1])
580             return lastLine;
581     }
582
583     int high = lineCount;
584     int low = -1;
585     int index = lineCount;
586     while (high - low > 1) {
587         index = (high + low) / 2;
588         int lineStart = lines[index][0];
589         int lineEnd = lineStart + lines[index][1] - 1;
590         if (position <= lineStart) {
591             high = index;
592         } else if (position <= lineEnd) {
593             high = index;
594             break;
595         } else {
596             low = index;
597         }
598     }
599     return high;
600 }
601 /**
602  * Returns the line index at the given physical offset.
603  * <p>
604  *
605  * @param position physical character offset (i.e., includes gap)
606  * @return the line index
607  */

608 int getLineAtPhysicalOffset(int position){
609     int high = lineCount;
610     int low = -1;
611     int index = lineCount;
612     while (high - low > 1) {
613         index = (high + low) / 2;
614         int lineStart = lines[index][0];
615         int lineEnd = lineStart + lines[index][1] - 1;
616         if (position <= lineStart) {
617             high = index;
618         } else if (position <= lineEnd) {
619             high = index;
620             break;
621         } else {
622             low = index;
623         }
624     }
625     return high;
626 }
627 /**
628  * Returns the logical offset of the given line.
629  * <p>
630  *
631  * @param lineIndex index of line
632  * @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.
634  * @exception IllegalArgumentException <ul>
635  * <li>ERROR_INVALID_ARGUMENT when lineIndex is out of range</li>
636  * </ul>
637  */

638 public int getOffsetAtLine(int lineIndex) {
639     if (lineIndex == 0) return 0;
640     if ((lineIndex >= lineCount) || (lineIndex < 0)) error(SWT.ERROR_INVALID_ARGUMENT);
641     int start = lines[lineIndex][0];
642     if (start > gapEnd) {
643         return start - (gapEnd - gapStart);
644     } else {
645         return start;
646     }
647 }
648 /**
649  * Increases the line indexes array to accommodate more lines.
650  * <p>
651  *
652  * @param numLines the number to increase the array by
653  */

654 void expandLinesBy(int numLines) {
655     int size = lines.length;
656     if (size - lineCount >= numLines) {
657         return;
658     }
659     int[][] newLines = new int[size+Math.max(10, numLines)][2];
660     System.arraycopy(lines, 0, newLines, 0, size);
661     lines = newLines;
662 }
663 /**
664  * Reports an SWT error.
665  * <p>
666  *
667  * @param code the error code
668  */

669 void error (int code) {
670     SWT.error(code);
671 }
672 /**
673  * Returns whether or not a gap exists in the text store.
674  * <p>
675  *
676  * @return true if gap exists, false otherwise
677  */

678 boolean gapExists() {
679     return gapStart != gapEnd;
680 }
681 /**
682  * Returns a string representing the continuous content of
683  * the text store.
684  * <p>
685  *
686  * @param start the physical start offset of the text to return
687  * @param length the physical length of the text to return
688  * @return the text
689  */

690 String JavaDoc getPhysicalText(int start, int length) {
691     return new String JavaDoc(textStore, start, length);
692 }
693 /**
694  * Returns a string representing the logical content of
695  * the text store (i.e., gap stripped out).
696  * <p>
697  *
698  * @param start the logical start offset of the text to return
699  * @param length the logical length of the text to return
700  * @return the text
701  */

702 public String JavaDoc getTextRange(int start, int length) {
703     if (textStore == null)
704         return "";
705     if (length == 0)
706         return "";
707     int end= start + length;
708     if (!gapExists() || (end < gapStart))
709         return new String JavaDoc(textStore, start, length);
710     if (gapStart < start) {
711         int gapLength= gapEnd - gapStart;
712         return new String JavaDoc(textStore, start + gapLength , length);
713     }
714     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
715     buf.append(textStore, start, gapStart - start);
716     buf.append(textStore, gapEnd, end - gapStart);
717     return buf.toString();
718 }
719 /**
720  * Removes the specified <code>TextChangeListener</code>.
721  * <p>
722  *
723  * @param listener the listener
724  * @exception IllegalArgumentException <ul>
725  * <li>ERROR_NULL_ARGUMENT when listener is null</li>
726  * </ul>
727  */

728 public void removeTextChangeListener(TextChangeListener listener){
729     if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
730     for (int i = 0; i < textListeners.size(); i++) {
731         TypedListener typedListener = (TypedListener) textListeners.elementAt(i);
732         if (typedListener.getEventListener () == listener) {
733             textListeners.removeElementAt(i);
734             break;
735         }
736     }
737 }
738 /**
739  * 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.
741  * <p>
742  *
743  * When sending the TextChangingEvent, <code>newLineCount</code> is the number of
744  * 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
746  * that occurs visually. For example:
747  * <ul>
748  * <li>(replaceText,newText) ==> (replaceLineCount,newLineCount)
749  * <li>("","\n") ==> (0,1)
750  * <li>("\n\n","a") ==> (2,0)
751  * </ul>
752  * </p>
753  *
754  * @param start start offset of text to replace
755  * @param replaceLength start offset of text to replace
756  * @param newText start offset of text to replace
757  *
758  * @exception SWTException <ul>
759  * <li>ERROR_INVALID_ARGUMENT when the text change results in a multi byte
760  * line delimiter being split or partially deleted. Splitting a line
761  * 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>
763  * </ul>
764  */

765 public void replaceTextRange(int start, int replaceLength, String JavaDoc newText){
766     // check for invalid replace operations
767
if (!isValidReplace(start, replaceLength, newText)) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
768
769     // inform listeners
770
StyledTextEvent event = new StyledTextEvent(this);
771     event.type = StyledText.TextChanging;
772     event.start = start;
773     event.replaceLineCount = lineCount(start, replaceLength);
774     event.text = newText;
775     event.newLineCount = lineCount(newText);
776     event.replaceCharCount = replaceLength;
777     event.newCharCount = newText.length();
778     sendTextEvent(event);
779
780     // first delete the text to be replaced
781
delete(start, replaceLength, event.replaceLineCount + 1);
782     // then insert the new text
783
insert(start, newText);
784     // inform listeners
785
event = new StyledTextEvent(this);
786     event.type = StyledText.TextChanged;
787     sendTextEvent(event);
788 }
789 /**
790  * Sends the text listeners the TextChanged event.
791  */

792 void sendTextEvent(StyledTextEvent event) {
793     for (int i = 0; i < textListeners.size(); i++) {
794         ((StyledTextListener)textListeners.elementAt(i)).handleEvent(event);
795     }
796 }
797 /**
798  * Sets the content to text and removes the gap since there are no sensible predictions
799  * about where the next change will occur.
800  * <p>
801  *
802  * @param text the text
803  */

804 public void setText (String JavaDoc text){
805     textStore = text.toCharArray();
806     gapStart = -1;
807     gapEnd = -1;
808     expandExp = 1;
809     indexLines();
810     StyledTextEvent event = new StyledTextEvent(this);
811     event.type = StyledText.TextSet;
812     event.text = "";
813     sendTextEvent(event);
814 }
815 /**
816  * Deletes text.
817  * <p>
818  * @param position the position at which the text to delete starts
819  * @param length the length of the text to delete
820  * @param numLines the number of lines that are being deleted
821  */

822 void delete(int position, int length, int numLines) {
823     if (length == 0) return;
824         
825     int startLine = getLineAtOffset(position);
826     int startLineOffset = getOffsetAtLine(startLine);
827     int endLine = getLineAtOffset(position + length);
828
829     String JavaDoc endText = "";
830     boolean splittingDelimiter = false;
831     if (position + length < getCharCount()) {
832         endText = getTextRange(position + length - 1, 2);
833         if ((endText.charAt(0) == SWT.CR) && (endText.charAt(1) == SWT.LF)) {
834             splittingDelimiter = true;
835         }
836     }
837
838     adjustGap(position + length, -length, startLine);
839     int [][] oldLines = indexLines(position, length + (gapEnd - gapStart), numLines);
840     
841     // enlarge the gap - the gap can be enlarged either to the
842
// right or left
843
if (position + length == gapStart) {
844         gapStart -= length;
845     } else {
846         gapEnd += length;
847     }
848
849     // figure out the length of the new concatenated line, do so by
850
// finding the first line delimiter after position
851
int j = position;
852     boolean eol = false;
853     while (j < textStore.length && !eol) {
854         if (j < gapStart || j >= gapEnd) {
855             char ch = textStore[j];
856             if (isDelimiter(ch)) {
857                 if (j + 1 < textStore.length) {
858                     if (ch == SWT.CR && (textStore[j+1] == SWT.LF)) {
859                         j++;
860                     }
861                 }
862                 eol = true;
863             }
864         }
865         j++;
866     }
867     // update the line where the deletion started
868
lines[startLine][1] = (position - startLineOffset) + (j - position);
869     // figure out the number of lines that have been deleted
870
int numOldLines = oldLines.length - 1;
871     if (splittingDelimiter) numOldLines -= 1;
872     // shift up the lines after the last deleted line, no need to update
873
// the offset or length of the lines
874
for (int i = endLine + 1; i < lineCount; i++) {
875         lines[i - numOldLines] = lines[i];
876     }
877     lineCount -= numOldLines;
878     gapLine = getLineAtPhysicalOffset(gapStart);
879 }
880 }
881
Popular Tags