1 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 ; 17 18 class DefaultContent implements StyledTextContent { 19 private final static String LineDelimiter = System.getProperty("line.separator"); 20 21 Vector textListeners = new Vector (); char[] textStore = new char[0]; int gapStart = -1; int gapEnd = -1; int gapLine = -1; int highWatermark = 300; 27 int lowWatermark = 50; 28 29 int[][] lines = new int[50][2]; int lineCount = 0; int expandExp = 1; int replaceExpandExp = 1; 34 38 DefaultContent() { 39 super(); 40 setText(""); 41 } 42 50 void addLineIndex(int start, int length) { 51 int size = lines.length; 52 if (lineCount == size) { 53 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 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 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 112 void adjustGap(int position, int sizeHint, int line) { 113 if (position == gapStart) { 114 int size = (gapEnd - gapStart) - sizeHint; 116 if (lowWatermark <= size && size <= highWatermark) 117 return; 118 } else if ((position + sizeHint == gapStart) && (sizeHint < 0)) { 119 int size = (gapEnd - gapStart) - sizeHint; 121 if (lowWatermark <= size && size <= highWatermark) 122 return; 123 } 124 moveAndResizeGap(position, sizeHint, line); 125 } 126 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 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 162 boolean isDelimiter(char ch) { 163 if (ch == SWT.CR) return true; 164 if (ch == SWT.LF) return true; 165 return false; 166 } 167 177 protected boolean isValidReplace(int start, int replaceLength, String newText){ 178 if (replaceLength == 0) { 179 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 char startChar = getTextRange(start, 1).charAt(0); 190 if (startChar == '\n') { 191 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 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 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 } else { 230 char ch = textStore[location]; 231 if (ch == SWT.CR) { 232 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 262 void insert(int position, String 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 int startLineOffset = getOffsetAtLine(startLine); 274 int startLineLength = getPhysicalLine(startLine).length(); 277 278 if (change > 0) { 279 gapStart += (change); 281 for (int i = 0; i < text.length(); i++) { 282 textStore[position + i]= text.charAt(i); 283 } 284 } 285 286 int [][] newLines = indexLines(startLineOffset, startLineLength, 10); 288 int numNewLines = newLines.length - 1; 290 if (newLines[numNewLines][1] == 0) { 291 if (endInsert) { 293 numNewLines += 1; 297 } else { 298 numNewLines -= 1; 299 } 300 } 301 302 expandLinesBy(numNewLines); 304 for (int i = lineCount - 1; i > startLine; i--) { 306 lines[i + numNewLines]=lines[i]; 307 } 308 for (int i = 0; i < numNewLines; i++) { 310 newLines[i][0] += startLineOffset; 311 lines[startLine + i]=newLines[i]; 312 } 313 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 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 if (gapExists()) { 343 lines[gapLine][1] = lines[gapLine][1] - oldSize; 345 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 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 if (gapExists()) { 385 gapLine = newGapLine; 386 int gapLength = gapEnd - gapStart; 388 lines[gapLine][1] = lines[gapLine][1] + (gapLength); 389 for (int i = gapLine + 1; i < lineCount; i++) { 391 lines[i][0] = lines[i][0] + gapLength; 392 } 393 } 394 } 395 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 } else { 417 char ch = textStore[i]; 418 if (ch == SWT.CR) { 419 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 444 int lineCount(String 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 463 public int getCharCount() { 464 int length = gapEnd - gapStart; 465 return (textStore.length - length); 466 } 467 477 public String 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 while ((length - 1 >= 0) && isDelimiter(textStore[start+length-1])) { 485 length--; 486 } 487 return new String (textStore, start, length); 488 } else { 489 StringBuffer buf = new StringBuffer (); 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 510 public String getLineDelimiter() { 511 return LineDelimiter; 512 } 513 519 String 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 return new String (textStore, start, length); 526 } else { 527 StringBuffer buffer = new StringBuffer (); 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 542 String getPhysicalLine(int index) { 543 int start = lines[index][0]; 544 int length = lines[index][1]; 545 return getPhysicalText(start, length); 546 } 547 550 public int getLineCount(){ 551 return lineCount; 552 } 553 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 = charPosition; 569 } else { 570 position = charPosition + (gapEnd - gapStart); 572 } 573 574 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 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 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 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 669 void error (int code) { 670 SWT.error(code); 671 } 672 678 boolean gapExists() { 679 return gapStart != gapEnd; 680 } 681 690 String getPhysicalText(int start, int length) { 691 return new String (textStore, start, length); 692 } 693 702 public String 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 (textStore, start, length); 710 if (gapStart < start) { 711 int gapLength= gapEnd - gapStart; 712 return new String (textStore, start + gapLength , length); 713 } 714 StringBuffer buf = new StringBuffer (); 715 buf.append(textStore, start, gapStart - start); 716 buf.append(textStore, gapEnd, end - gapStart); 717 return buf.toString(); 718 } 719 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 765 public void replaceTextRange(int start, int replaceLength, String newText){ 766 if (!isValidReplace(start, replaceLength, newText)) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 768 769 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 delete(start, replaceLength, event.replaceLineCount + 1); 782 insert(start, newText); 784 event = new StyledTextEvent(this); 786 event.type = StyledText.TextChanged; 787 sendTextEvent(event); 788 } 789 792 void sendTextEvent(StyledTextEvent event) { 793 for (int i = 0; i < textListeners.size(); i++) { 794 ((StyledTextListener)textListeners.elementAt(i)).handleEvent(event); 795 } 796 } 797 804 public void setText (String 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 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 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 if (position + length == gapStart) { 844 gapStart -= length; 845 } else { 846 gapEnd += length; 847 } 848 849 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 lines[startLine][1] = (position - startLineOffset) + (j - position); 869 int numOldLines = oldLines.length - 1; 871 if (splittingDelimiter) numOldLines -= 1; 872 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 |