1 7 package javax.swing.text; 8 9 import java.util.Vector ; 10 import java.io.IOException ; 11 import java.io.ObjectInputStream ; 12 import java.io.Serializable ; 13 import javax.swing.undo.AbstractUndoableEdit ; 14 import javax.swing.undo.CannotRedoException ; 15 import javax.swing.undo.CannotUndoException ; 16 import javax.swing.undo.UndoableEdit ; 17 import javax.swing.SwingUtilities ; 18 import java.lang.ref.WeakReference ; 19 import java.lang.ref.ReferenceQueue ; 20 21 44 public class GapContent extends GapVector implements AbstractDocument.Content , Serializable { 45 46 49 public GapContent() { 50 this(10); 51 } 52 53 61 public GapContent(int initialLength) { 62 super(Math.max(initialLength,2)); 63 char[] implied = new char[1]; 64 implied[0] = '\n'; 65 replace(0, 0, implied, implied.length); 66 67 marks = new MarkVector(); 68 search = new MarkData(0); 69 queue = new ReferenceQueue (); 70 } 71 72 76 protected Object allocateArray(int len) { 77 return new char[len]; 78 } 79 80 83 protected int getArrayLength() { 84 char[] carray = (char[]) getArray(); 85 return carray.length; 86 } 87 88 90 96 public int length() { 97 int len = getArrayLength() - (getGapEnd() - getGapStart()); 98 return len; 99 } 100 101 110 public UndoableEdit insertString(int where, String str) throws BadLocationException { 111 if (where > length() || where < 0) { 112 throw new BadLocationException ("Invalid insert", length()); 113 } 114 char[] chars = str.toCharArray(); 115 replace(where, 0, chars, chars.length); 116 return new InsertUndo(where, str.length()); 117 } 118 119 128 public UndoableEdit remove(int where, int nitems) throws BadLocationException { 129 if (where + nitems >= length()) { 130 throw new BadLocationException ("Invalid remove", length() + 1); 131 } 132 String removedString = getString(where, nitems); 133 UndoableEdit edit = new RemoveUndo(where, removedString); 134 replace(where, nitems, empty, 0); 135 return edit; 136 137 } 138 139 148 public String getString(int where, int len) throws BadLocationException { 149 Segment s = new Segment (); 150 getChars(where, len, s); 151 return new String (s.array, s.offset, s.count); 152 } 153 154 166 public void getChars(int where, int len, Segment chars) throws BadLocationException { 167 int end = where + len; 168 if (where < 0 || end < 0) { 169 throw new BadLocationException ("Invalid location", -1); 170 } 171 if (end > length() || where > length()) { 172 throw new BadLocationException ("Invalid location", length() + 1); 173 } 174 int g0 = getGapStart(); 175 int g1 = getGapEnd(); 176 char[] array = (char[]) getArray(); 177 if ((where + len) <= g0) { 178 chars.array = array; 180 chars.offset = where; 181 } else if (where >= g0) { 182 chars.array = array; 184 chars.offset = g1 + where - g0; 185 } else { 186 int before = g0 - where; 188 if (chars.isPartialReturn()) { 189 chars.array = array; 191 chars.offset = where; 192 chars.count = before; 193 return; 194 } 195 chars.array = new char[len]; 197 chars.offset = 0; 198 System.arraycopy(array, where, chars.array, 0, before); 199 System.arraycopy(array, g1, chars.array, before, len - before); 200 } 201 chars.count = len; 202 } 203 204 212 public Position createPosition(int offset) throws BadLocationException { 213 while ( queue.poll() != null ) { 214 unusedMarks++; 215 } 216 if (unusedMarks > Math.max(5, (marks.size() / 10))) { 217 removeUnusedMarks(); 218 } 219 int g0 = getGapStart(); 220 int g1 = getGapEnd(); 221 int index = (offset < g0) ? offset : offset + (g1 - g0); 222 search.index = index; 223 int sortIndex = findSortIndex(search); 224 MarkData m; 225 StickyPosition position; 226 if (sortIndex < marks.size() 227 && (m = marks.elementAt(sortIndex)).index == index 228 && (position = m.getPosition()) != null) { 229 } else { 231 position = new StickyPosition(); 232 m = new MarkData(index,position,queue); 233 position.setMark(m); 234 marks.insertElementAt(m, sortIndex); 235 } 236 237 return position; 238 } 239 240 248 final class MarkData extends WeakReference { 249 250 MarkData(int index) { 251 super(null); 252 this.index = index; 253 } 254 MarkData(int index, StickyPosition position, ReferenceQueue queue) { 255 super(position, queue); 256 this.index = index; 257 } 258 259 265 public final int getOffset() { 266 int g0 = getGapStart(); 267 int g1 = getGapEnd(); 268 int offs = (index < g0) ? index : index - (g1 - g0); 269 return Math.max(offs, 0); 270 } 271 272 StickyPosition getPosition() { 273 return (StickyPosition)get(); 274 } 275 int index; 276 } 277 278 final class StickyPosition implements Position { 279 280 StickyPosition() { 281 } 282 283 void setMark(MarkData mark) { 284 this.mark = mark; 285 } 286 287 public final int getOffset() { 288 return mark.getOffset(); 289 } 290 291 public String toString() { 292 return Integer.toString(getOffset()); 293 } 294 295 MarkData mark; 296 } 297 298 300 private static final char[] empty = new char[0]; 301 private transient MarkVector marks; 302 303 308 private transient MarkData search; 309 310 313 private transient int unusedMarks = 0; 314 315 private transient ReferenceQueue queue; 316 317 final static int GROWTH_SIZE = 1024 * 512; 318 319 321 325 protected void shiftEnd(int newSize) { 326 int oldGapEnd = getGapEnd(); 327 328 super.shiftEnd(newSize); 329 330 int dg = getGapEnd() - oldGapEnd; 332 int adjustIndex = findMarkAdjustIndex(oldGapEnd); 333 int n = marks.size(); 334 for (int i = adjustIndex; i < n; i++) { 335 MarkData mark = marks.elementAt(i); 336 mark.index += dg; 337 } 338 } 339 340 344 int getNewArraySize(int reqSize) { 345 if (reqSize < GROWTH_SIZE) { 346 return super.getNewArraySize(reqSize); 347 } else { 348 return reqSize + GROWTH_SIZE; 349 } 350 } 351 352 358 protected void shiftGap(int newGapStart) { 359 int oldGapStart = getGapStart(); 360 int dg = newGapStart - oldGapStart; 361 int oldGapEnd = getGapEnd(); 362 int newGapEnd = oldGapEnd + dg; 363 int gapSize = oldGapEnd - oldGapStart; 364 365 super.shiftGap(newGapStart); 367 368 if (dg > 0) { 370 int adjustIndex = findMarkAdjustIndex(oldGapStart); 372 int n = marks.size(); 373 for (int i = adjustIndex; i < n; i++) { 374 MarkData mark = marks.elementAt(i); 375 if (mark.index >= newGapEnd) { 376 break; 377 } 378 mark.index -= gapSize; 379 } 380 } else if (dg < 0) { 381 int adjustIndex = findMarkAdjustIndex(newGapStart); 383 int n = marks.size(); 384 for (int i = adjustIndex; i < n; i++) { 385 MarkData mark = marks.elementAt(i); 386 if (mark.index >= oldGapEnd) { 387 break; 388 } 389 mark.index += gapSize; 390 } 391 } 392 resetMarksAtZero(); 393 } 394 395 399 protected void resetMarksAtZero() { 400 if (marks != null && getGapStart() == 0) { 401 int g1 = getGapEnd(); 402 for (int counter = 0, maxCounter = marks.size(); 403 counter < maxCounter; counter++) { 404 MarkData mark = marks.elementAt(counter); 405 if (mark.index <= g1) { 406 mark.index = 0; 407 } 408 else { 409 break; 410 } 411 } 412 } 413 } 414 415 423 protected void shiftGapStartDown(int newGapStart) { 424 int adjustIndex = findMarkAdjustIndex(newGapStart); 426 int n = marks.size(); 427 int g0 = getGapStart(); 428 int g1 = getGapEnd(); 429 for (int i = adjustIndex; i < n; i++) { 430 MarkData mark = marks.elementAt(i); 431 if (mark.index > g0) { 432 break; 434 } 435 mark.index = g1; 436 } 437 438 super.shiftGapStartDown(newGapStart); 440 441 resetMarksAtZero(); 442 } 443 444 452 protected void shiftGapEndUp(int newGapEnd) { 453 int adjustIndex = findMarkAdjustIndex(getGapEnd()); 454 int n = marks.size(); 455 for (int i = adjustIndex; i < n; i++) { 456 MarkData mark = marks.elementAt(i); 457 if (mark.index >= newGapEnd) { 458 break; 459 } 460 mark.index = newGapEnd; 461 } 462 463 super.shiftGapEndUp(newGapEnd); 465 466 resetMarksAtZero(); 467 } 468 469 476 final int compare(MarkData o1, MarkData o2) { 477 if (o1.index < o2.index) { 478 return -1; 479 } else if (o1.index > o2.index) { 480 return 1; 481 } else { 482 return 0; 483 } 484 } 485 486 490 final int findMarkAdjustIndex(int searchIndex) { 491 search.index = Math.max(searchIndex, 1); 492 int index = findSortIndex(search); 493 494 for (int i = index - 1; i >= 0; i--) { 497 MarkData d = marks.elementAt(i); 498 if (d.index != search.index) { 499 break; 500 } 501 index -= 1; 502 } 503 return index; 504 } 505 506 512 final int findSortIndex(MarkData o) { 513 int lower = 0; 514 int upper = marks.size() - 1; 515 int mid = 0; 516 517 if (upper == -1) { 518 return 0; 519 } 520 521 int cmp = 0; 522 MarkData last = marks.elementAt(upper); 523 cmp = compare(o, last); 524 if (cmp > 0) 525 return upper + 1; 526 527 while (lower <= upper) { 528 mid = lower + ((upper - lower) / 2); 529 MarkData entry = marks.elementAt(mid); 530 cmp = compare(o, entry); 531 532 if (cmp == 0) { 533 return mid; 535 } else if (cmp < 0) { 536 upper = mid - 1; 537 } else { 538 lower = mid + 1; 539 } 540 } 541 542 return (cmp < 0) ? mid : mid + 1; 544 } 545 546 550 final void removeUnusedMarks() { 551 int n = marks.size(); 552 MarkVector cleaned = new MarkVector(n); 553 for (int i = 0; i < n; i++) { 554 MarkData mark = marks.elementAt(i); 555 if (mark.get() != null) { 556 cleaned.addElement(mark); 557 } 558 } 559 marks = cleaned; 560 unusedMarks = 0; 561 } 562 563 564 static class MarkVector extends GapVector { 565 566 MarkVector() { 567 super(); 568 } 569 570 MarkVector(int size) { 571 super(size); 572 } 573 574 578 protected Object allocateArray(int len) { 579 return new MarkData[len]; 580 } 581 582 585 protected int getArrayLength() { 586 MarkData[] marks = (MarkData[]) getArray(); 587 return marks.length; 588 } 589 590 593 public int size() { 594 int len = getArrayLength() - (getGapEnd() - getGapStart()); 595 return len; 596 } 597 598 601 public void insertElementAt(MarkData m, int index) { 602 oneMark[0] = m; 603 replace(index, 0, oneMark, 1); 604 } 605 606 609 public void addElement(MarkData m) { 610 insertElementAt(m, size()); 611 } 612 613 616 public MarkData elementAt(int index) { 617 int g0 = getGapStart(); 618 int g1 = getGapEnd(); 619 MarkData[] array = (MarkData[]) getArray(); 620 if (index < g0) { 621 return array[index]; 623 } else { 624 index += g1 - g0; 626 return array[index]; 627 } 628 } 629 630 636 protected void replaceRange(int start, int end, Object [] marks) { 637 int g0 = getGapStart(); 638 int g1 = getGapEnd(); 639 int index = start; 640 int newIndex = 0; 641 Object [] array = (Object []) getArray(); 642 if (start >= g0) { 643 index += (g1 - g0); 645 end += (g1 - g0); 646 } 647 else if (end >= g0) { 648 end += (g1 - g0); 650 while (index < g0) { 651 array[index++] = marks[newIndex++]; 652 } 653 index = g1; 654 } 655 else { 656 while (index < end) { 658 array[index++] = marks[newIndex++]; 659 } 660 } 661 while (index < end) { 662 array[index++] = marks[newIndex++]; 663 } 664 } 665 666 MarkData[] oneMark = new MarkData[1]; 667 668 } 669 670 672 private void readObject(ObjectInputStream s) 673 throws ClassNotFoundException , IOException { 674 s.defaultReadObject(); 675 marks = new MarkVector(); 676 search = new MarkData(0); 677 queue = new ReferenceQueue (); 678 } 679 680 681 683 695 protected Vector getPositionsInRange(Vector v, int offset, int length) { 696 int endOffset = offset + length; 697 int startIndex; 698 int endIndex; 699 int g0 = getGapStart(); 700 int g1 = getGapEnd(); 701 702 if (offset < g0) { 704 if (offset == 0) { 705 startIndex = 0; 707 } 708 else { 709 startIndex = findMarkAdjustIndex(offset); 710 } 711 if (endOffset >= g0) { 712 endIndex = findMarkAdjustIndex(endOffset + (g1 - g0) + 1); 713 } 714 else { 715 endIndex = findMarkAdjustIndex(endOffset + 1); 716 } 717 } 718 else { 719 startIndex = findMarkAdjustIndex(offset + (g1 - g0)); 720 endIndex = findMarkAdjustIndex(endOffset + (g1 - g0) + 1); 721 } 722 723 Vector placeIn = (v == null) ? new Vector (Math.max(1, endIndex - 724 startIndex)) : v; 725 726 for (int counter = startIndex; counter < endIndex; counter++) { 727 placeIn.addElement(new UndoPosRef(marks.elementAt(counter))); 728 } 729 return placeIn; 730 } 731 732 741 protected void updateUndoPositions(Vector positions, int offset, 742 int length) { 743 int endOffset = offset + length; 745 int g1 = getGapEnd(); 746 int startIndex; 747 int endIndex = findMarkAdjustIndex(g1 + 1); 748 749 if (offset != 0) { 750 startIndex = findMarkAdjustIndex(g1); 751 } 752 else { 753 startIndex = 0; 754 } 755 756 for(int counter = positions.size() - 1; counter >= 0; counter--) { 758 UndoPosRef ref = (UndoPosRef)positions.elementAt(counter); 759 ref.resetLocation(endOffset, g1); 760 } 761 if (startIndex < endIndex) { 766 Object [] sorted = new Object [endIndex - startIndex]; 767 int addIndex = 0; 768 int counter; 769 if (offset == 0) { 770 for (counter = startIndex; counter < endIndex; counter++) { 774 MarkData mark = marks.elementAt(counter); 775 if (mark.index == 0) { 776 sorted[addIndex++] = mark; 777 } 778 } 779 for (counter = startIndex; counter < endIndex; counter++) { 780 MarkData mark = marks.elementAt(counter); 781 if (mark.index != 0) { 782 sorted[addIndex++] = mark; 783 } 784 } 785 } 786 else { 787 for (counter = startIndex; counter < endIndex; counter++) { 788 MarkData mark = marks.elementAt(counter); 789 if (mark.index != g1) { 790 sorted[addIndex++] = mark; 791 } 792 } 793 for (counter = startIndex; counter < endIndex; counter++) { 794 MarkData mark = marks.elementAt(counter); 795 if (mark.index == g1) { 796 sorted[addIndex++] = mark; 797 } 798 } 799 } 800 marks.replaceRange(startIndex, endIndex, sorted); 802 } 803 } 804 805 809 final class UndoPosRef { 810 UndoPosRef(MarkData rec) { 811 this.rec = rec; 812 this.undoLocation = rec.getOffset(); 813 } 814 815 822 protected void resetLocation(int endOffset, int g1) { 823 if (undoLocation != endOffset) { 824 this.rec.index = undoLocation; 825 } 826 else { 827 this.rec.index = g1; 828 } 829 } 830 831 832 protected int undoLocation; 833 834 protected MarkData rec; 835 } 837 838 841 class InsertUndo extends AbstractUndoableEdit { 842 protected InsertUndo(int offset, int length) { 843 super(); 844 this.offset = offset; 845 this.length = length; 846 } 847 848 public void undo() throws CannotUndoException { 849 super.undo(); 850 try { 851 posRefs = getPositionsInRange(null, offset, length); 853 string = getString(offset, length); 854 remove(offset, length); 855 } catch (BadLocationException bl) { 856 throw new CannotUndoException (); 857 } 858 } 859 860 public void redo() throws CannotRedoException { 861 super.redo(); 862 try { 863 insertString(offset, string); 864 string = null; 865 if(posRefs != null) { 867 updateUndoPositions(posRefs, offset, length); 868 posRefs = null; 869 } 870 } catch (BadLocationException bl) { 871 throw new CannotRedoException (); 872 } 873 } 874 875 876 protected int offset; 877 878 protected int length; 879 881 protected String string; 882 884 protected Vector posRefs; 885 } 887 888 891 class RemoveUndo extends AbstractUndoableEdit { 892 protected RemoveUndo(int offset, String string) { 893 super(); 894 this.offset = offset; 895 this.string = string; 896 this.length = string.length(); 897 posRefs = getPositionsInRange(null, offset, length); 898 } 899 900 public void undo() throws CannotUndoException { 901 super.undo(); 902 try { 903 insertString(offset, string); 904 if(posRefs != null) { 906 updateUndoPositions(posRefs, offset, length); 907 posRefs = null; 908 } 909 string = null; 910 } catch (BadLocationException bl) { 911 throw new CannotUndoException (); 912 } 913 } 914 915 public void redo() throws CannotRedoException { 916 super.redo(); 917 try { 918 string = getString(offset, length); 919 posRefs = getPositionsInRange(null, offset, length); 921 remove(offset, length); 922 } catch (BadLocationException bl) { 923 throw new CannotRedoException (); 924 } 925 } 926 927 928 protected int offset; 929 930 protected int length; 931 932 protected String string; 933 935 protected Vector posRefs; 936 } } 938 939 940 | Popular Tags |