KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > GapContent


1 /*
2  * @(#)GapContent.java 1.21 01/12/03
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.text;
8
9 import java.util.Vector JavaDoc;
10 import java.io.IOException JavaDoc;
11 import java.io.ObjectInputStream JavaDoc;
12 import java.io.Serializable JavaDoc;
13 import javax.swing.undo.AbstractUndoableEdit JavaDoc;
14 import javax.swing.undo.CannotRedoException JavaDoc;
15 import javax.swing.undo.CannotUndoException JavaDoc;
16 import javax.swing.undo.UndoableEdit JavaDoc;
17 import javax.swing.SwingUtilities JavaDoc;
18 import java.lang.ref.WeakReference JavaDoc;
19 import java.lang.ref.ReferenceQueue JavaDoc;
20
21 /**
22  * An implementation of the AbstractDocument.Content interface
23  * implemented using a gapped buffer similar to that used by emacs.
24  * The underlying storage is a array of unicode characters with
25  * a gap somewhere. The gap is moved to the location of changes
26  * to take advantage of common behavior where most changes are
27  * in the same location. Changes that occur at a gap boundary are
28  * generally cheap and moving the gap is generally cheaper than
29  * moving the array contents directly to accomodate the change.
30  * <p>
31  * The positions tracking change are also generally cheap to
32  * maintain. The Position implementations (marks) store the array
33  * index and can easily calculate the sequential position from
34  * the current gap location. Changes only require update to the
35  * the marks between the old and new gap boundaries when the gap
36  * is moved, so generally updating the marks is pretty cheap.
37  * The marks are stored sorted so they can be located quickly
38  * with a binary search. This increases the cost of adding a
39  * mark, and decreases the cost of keeping the mark updated.
40  *
41  * @author Timothy Prinzing
42  * @version 1.21 12/03/01
43  */

44 public class GapContent extends GapVector JavaDoc implements AbstractDocument.Content JavaDoc, Serializable JavaDoc {
45
46     /**
47      * Creates a new GapContent object. Initial size defaults to 10.
48      */

49     public GapContent() {
50     this(10);
51     }
52
53     /**
54      * Creates a new GapContent object, with the initial
55      * size specified. The initial size will not be allowed
56      * to go below 2, to give room for the implied break and
57      * the gap.
58      *
59      * @param initialLength the initial size
60      */

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 JavaDoc();
70     }
71     
72     /**
73      * Allocate an array to store items of the type
74      * appropriate (which is determined by the subclass).
75      */

76     protected Object JavaDoc allocateArray(int len) {
77     return new char[len];
78     }
79     
80     /**
81      * Get the length of the allocated array.
82      */

83     protected int getArrayLength() {
84     char[] carray = (char[]) getArray();
85     return carray.length;
86     }
87
88     // --- AbstractDocument.Content methods -------------------------
89

90     /**
91      * Returns the length of the content.
92      *
93      * @return the length >= 1
94      * @see AbstractDocument.Content#length
95      */

96     public int length() {
97     int len = getArrayLength() - (getGapEnd() - getGapStart());
98     return len;
99     }
100
101     /**
102      * Inserts a string into the content.
103      *
104      * @param where the starting position >= 0, < length()
105      * @param str the non-null string to insert
106      * @return an UndoableEdit object for undoing
107      * @exception BadLocationException if the specified position is invalid
108      * @see AbstractDocument.Content#insertString
109      */

110     public UndoableEdit JavaDoc insertString(int where, String JavaDoc str) throws BadLocationException JavaDoc {
111     if (where > length() || where < 0) {
112         throw new BadLocationException JavaDoc("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     /**
120      * Removes part of the content.
121      *
122      * @param where the starting position >= 0, where + nitems < length()
123      * @param nitems the number of characters to remove >= 0
124      * @return an UndoableEdit object for undoing
125      * @exception BadLocationException if the specified position is invalid
126      * @see AbstractDocument.Content#remove
127      */

128     public UndoableEdit JavaDoc remove(int where, int nitems) throws BadLocationException JavaDoc {
129     if (where + nitems >= length()) {
130         throw new BadLocationException JavaDoc("Invalid remove", length() + 1);
131     }
132     String JavaDoc removedString = getString(where, nitems);
133     UndoableEdit JavaDoc edit = new RemoveUndo(where, removedString);
134     replace(where, nitems, empty, 0);
135     return edit;
136     
137     }
138
139     /**
140      * Retrieves a portion of the content.
141      *
142      * @param where the starting position >= 0
143      * @param len the length to retrieve >= 0
144      * @return a string representing the content
145      * @exception BadLocationException if the specified position is invalid
146      * @see AbstractDocument.Content#getString
147      */

148     public String JavaDoc getString(int where, int len) throws BadLocationException JavaDoc {
149     Segment JavaDoc s = new Segment JavaDoc();
150     getChars(where, len, s);
151     return new String JavaDoc(s.array, s.offset, s.count);
152     }
153
154     /**
155      * Retrieves a portion of the content. If the desired content spans
156      * the gap, we copy the content. If the desired content does not
157      * span the gap, the actual store is returned to avoid the copy since
158      * it is contiguous.
159      *
160      * @param where the starting position >= 0, where + len <= length()
161      * @param len the number of characters to retrieve >= 0
162      * @param chars the Segment object to return the characters in
163      * @exception BadLocationException if the specified position is invalid
164      * @see AbstractDocument.Content#getChars
165      */

166     public void getChars(int where, int len, Segment JavaDoc chars) throws BadLocationException JavaDoc {
167     int end = where + len;
168     if (where < 0 || end < 0) {
169         throw new BadLocationException JavaDoc("Invalid location", -1);
170     }
171     if (end > length() || where > length()) {
172         throw new BadLocationException JavaDoc("Invalid location", length() + 1);
173     }
174     int g0 = getGapStart();
175     int g1 = getGapEnd();
176     char[] array = (char[]) getArray();
177     if ((where + len) <= g0) {
178         // below gap
179
chars.array = array;
180         chars.offset = where;
181     } else if (where >= g0) {
182         // above gap
183
chars.array = array;
184         chars.offset = g1 + where - g0;
185     } else {
186         // spans the gap
187
int before = g0 - where;
188         if (chars.isPartialReturn()) {
189         // partial return allowed, return amount before the gap
190
chars.array = array;
191         chars.offset = where;
192         chars.count = before;
193         return;
194         }
195         // partial return not allowed, must copy
196
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     /**
205      * Creates a position within the content that will
206      * track change as the content is mutated.
207      *
208      * @param offset the offset to track >= 0
209      * @return the position
210      * @exception BadLocationException if the specified position is invalid
211      */

212     public Position JavaDoc createPosition(int offset) throws BadLocationException JavaDoc {
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         //position references the correct StickyPostition
230
} 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     /**
241      * Holds the data for a mark... separately from
242      * the real mark so that the real mark (Position
243      * that the caller of createPosition holds) can be
244      * collected if there are no more references to
245      * it. The update table holds only a reference
246      * to this data.
247      */

248     final class MarkData extends WeakReference JavaDoc {
249
250     MarkData(int index) {
251         super(null);
252         this.index = index;
253     }
254     MarkData(int index, StickyPosition position, ReferenceQueue JavaDoc queue) {
255         super(position, queue);
256         this.index = index;
257     }
258
259     /**
260      * Fetch the location in the contiguous sequence
261      * being modeled. The index in the gap array
262      * is held by the mark, so it is adjusted according
263      * to it's relationship to the gap.
264      */

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 JavaDoc {
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 JavaDoc toString() {
292         return Integer.toString(getOffset());
293     }
294
295     MarkData mark;
296     }
297
298     // --- variables --------------------------------------
299

300     private static final char[] empty = new char[0];
301     private transient MarkVector marks;
302
303     /**
304      * Record used for searching for the place to
305      * start updating mark indexs when the gap
306      * boundaries are moved.
307      */

308     private transient MarkData search;
309
310     /**
311      * The number of unused mark entries
312      */

313     private transient int unusedMarks = 0;
314
315     private transient ReferenceQueue JavaDoc queue;
316
317     final static int GROWTH_SIZE = 1024 * 512;
318
319     // --- gap management -------------------------------
320

321     /**
322      * Make the gap bigger, moving any necessary data and updating
323      * the appropriate marks
324      */

325     protected void shiftEnd(int newSize) {
326     int oldGapEnd = getGapEnd();
327
328     super.shiftEnd(newSize);
329
330     // Adjust marks.
331
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     /**
341      * Overridden to make growth policy less agressive for large
342      * text amount.
343      */

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     /**
353      * Move the start of the gap to a new location,
354      * without changing the size of the gap. This
355      * moves the data in the array and updates the
356      * marks accordingly.
357      */

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     // shift gap in the character array
366
super.shiftGap(newGapStart);
367
368     // update the marks
369
if (dg > 0) {
370         // Move gap up, move data and marks down.
371
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         // Move gap down, move data and marks up.
382
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     /**
396      * Resets all the marks that have an offset of 0 to have an index of
397      * zero as well.
398      */

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     /**
416      * Adjust the gap end downward. This doesn't move
417      * any data, but it does update any marks affected
418      * by the boundary change. All marks from the old
419      * gap start down to the new gap start are squeezed
420      * to the end of the gap (their location has been
421      * removed).
422      */

423     protected void shiftGapStartDown(int newGapStart) {
424     // Push aside all marks from oldGapStart down to newGapStart.
425
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         // no more marks to adjust
433
break;
434         }
435         mark.index = g1;
436     }
437
438     // shift the gap in the character array
439
super.shiftGapStartDown(newGapStart);
440
441     resetMarksAtZero();
442     }
443
444     /**
445      * Adjust the gap end upward. This doesn't move
446      * any data, but it does update any marks affected
447      * by the boundary change. All marks from the old
448      * gap end up to the new gap end are squeezed
449      * to the end of the gap (their location has been
450      * removed).
451      */

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     // shift the gap in the character array
464
super.shiftGapEndUp(newGapEnd);
465
466     resetMarksAtZero();
467     }
468
469     /**
470      * Compares two marks.
471      *
472      * @param o1 the first object
473      * @param o2 the second object
474      * @return < 0 if o1 < o2, 0 if the same, > 0 if o1 > o2
475      */

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     /**
487      * Finds the index to start mark adjustments given
488      * some search index.
489      */

490     final int findMarkAdjustIndex(int searchIndex) {
491     search.index = Math.max(searchIndex, 1);
492     int index = findSortIndex(search);
493
494     // return the first in the series
495
// (ie. there may be duplicates).
496
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     /**
507      * Finds the index of where to insert a new mark.
508      *
509      * @param o the mark to insert
510      * @return the index
511      */

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         // found a match
534
return mid;
535         } else if (cmp < 0) {
536         upper = mid - 1;
537         } else {
538         lower = mid + 1;
539         }
540     }
541
542     // didn't find it, but we indicate the index of where it would belong.
543
return (cmp < 0) ? mid : mid + 1;
544     }
545
546     /**
547      * Remove all unused marks out of the sorted collection
548      * of marks.
549      */

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 JavaDoc {
565
566     MarkVector() {
567         super();
568     }
569
570     MarkVector(int size) {
571         super(size);
572     }
573
574     /**
575      * Allocate an array to store items of the type
576      * appropriate (which is determined by the subclass).
577      */

578         protected Object JavaDoc allocateArray(int len) {
579         return new MarkData[len];
580     }
581     
582     /**
583      * Get the length of the allocated array
584      */

585         protected int getArrayLength() {
586         MarkData[] marks = (MarkData[]) getArray();
587         return marks.length;
588     }
589
590     /**
591      * Returns the number of marks currently held
592      */

593         public int size() {
594         int len = getArrayLength() - (getGapEnd() - getGapStart());
595         return len;
596     }
597
598     /**
599      * Inserts a mark into the vector
600      */

601     public void insertElementAt(MarkData m, int index) {
602         oneMark[0] = m;
603         replace(index, 0, oneMark, 1);
604     }
605
606     /**
607      * Add a mark to the end
608      */

609     public void addElement(MarkData m) {
610         insertElementAt(m, size());
611     }
612
613     /**
614      * Fetches the mark at the given index
615      */

616     public MarkData elementAt(int index) {
617         int g0 = getGapStart();
618         int g1 = getGapEnd();
619         MarkData[] array = (MarkData[]) getArray();
620         if (index < g0) {
621         // below gap
622
return array[index];
623         } else {
624         // above gap
625
index += g1 - g0;
626         return array[index];
627         }
628     }
629
630     /**
631      * Replaces the elements in the specified range with the passed
632      * in objects. This will NOT adjust the gap. The passed in indices
633      * do not account for the gap, they are the same as would be used
634      * int <code>elementAt</code>.
635      */

636     protected void replaceRange(int start, int end, Object JavaDoc[] marks) {
637         int g0 = getGapStart();
638         int g1 = getGapEnd();
639         int index = start;
640         int newIndex = 0;
641         Object JavaDoc[] array = (Object JavaDoc[]) getArray();
642         if (start >= g0) {
643         // Completely passed gap
644
index += (g1 - g0);
645         end += (g1 - g0);
646         }
647         else if (end >= g0) {
648         // straddles gap
649
end += (g1 - g0);
650         while (index < g0) {
651             array[index++] = marks[newIndex++];
652         }
653         index = g1;
654         }
655         else {
656         // below gap
657
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     // --- serialization -------------------------------------
671

672     private void readObject(ObjectInputStream JavaDoc s)
673       throws ClassNotFoundException JavaDoc, IOException JavaDoc {
674         s.defaultReadObject();
675     marks = new MarkVector();
676     search = new MarkData(0);
677         queue = new ReferenceQueue JavaDoc();
678     }
679
680
681     // --- undo support --------------------------------------
682

683     /**
684      * Returns a Vector containing instances of UndoPosRef for the
685      * Positions in the range
686      * <code>offset</code> to <code>offset</code> + <code>length</code>.
687      * If <code>v</code> is not null the matching Positions are placed in
688      * there. The vector with the resulting Positions are returned.
689      *
690      * @param v the Vector to use, with a new one created on null
691      * @param offset the starting offset >= 0
692      * @param length the length >= 0
693      * @return the set of instances
694      */

695     protected Vector JavaDoc getPositionsInRange(Vector JavaDoc 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     // Find the index of the marks.
703
if (offset < g0) {
704         if (offset == 0) {
705         // findMarkAdjustIndex start at 1!
706
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 JavaDoc placeIn = (v == null) ? new Vector JavaDoc(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     /**
733      * Resets the location for all the UndoPosRef instances
734      * in <code>positions</code>.
735      * <p>
736      * This is meant for internal usage, and is generally not of interest
737      * to subclasses.
738      *
739      * @param positions the UndoPosRef instances to reset
740      */

741     protected void updateUndoPositions(Vector JavaDoc positions, int offset,
742                        int length) {
743     // Find the indexs of the end points.
744
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     // Reset the location of the refenences.
757
for(int counter = positions.size() - 1; counter >= 0; counter--) {
758         UndoPosRef ref = (UndoPosRef)positions.elementAt(counter);
759         ref.resetLocation(endOffset, g1);
760     }
761     // We have to resort the marks in the range startIndex to endIndex.
762
// We can take advantage of the fact that it will be in
763
// increasing order, accept there will be a bunch of MarkData's with
764
// the index g1 (or 0 if offset == 0) interspersed throughout.
765
if (startIndex < endIndex) {
766         Object JavaDoc[] sorted = new Object JavaDoc[endIndex - startIndex];
767         int addIndex = 0;
768         int counter;
769         if (offset == 0) {
770         // If the offset is 0, the positions won't have incremented,
771
// have to do the reverse thing.
772
// Find the elements in startIndex whose index is 0
773
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         // And replace
801
marks.replaceRange(startIndex, endIndex, sorted);
802     }
803     }
804
805     /**
806      * Used to hold a reference to a Mark that is being reset as the
807      * result of removing from the content.
808      */

809     final class UndoPosRef {
810     UndoPosRef(MarkData rec) {
811         this.rec = rec;
812         this.undoLocation = rec.getOffset();
813     }
814
815     /**
816      * Resets the location of the Position to the offset when the
817      * receiver was instantiated.
818      *
819      * @param endOffset end location of inserted string.
820      * @param g1 resulting end of gap.
821      */

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     /** Previous Offset of rec. */
832     protected int undoLocation;
833     /** Mark to reset offset. */
834     protected MarkData rec;
835     } // End of GapContent.UndoPosRef
836

837
838     /**
839      * UnoableEdit created for inserts.
840      */

841     class InsertUndo extends AbstractUndoableEdit JavaDoc {
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 JavaDoc {
849         super.undo();
850         try {
851         // Get the Positions in the range being removed.
852
posRefs = getPositionsInRange(null, offset, length);
853         string = getString(offset, length);
854         remove(offset, length);
855         } catch (BadLocationException JavaDoc bl) {
856           throw new CannotUndoException JavaDoc();
857         }
858     }
859
860     public void redo() throws CannotRedoException JavaDoc {
861         super.redo();
862         try {
863         insertString(offset, string);
864         string = null;
865         // Update the Positions that were in the range removed.
866
if(posRefs != null) {
867             updateUndoPositions(posRefs, offset, length);
868             posRefs = null;
869         }
870         } catch (BadLocationException JavaDoc bl) {
871         throw new CannotRedoException JavaDoc();
872         }
873     }
874
875     /** Where string was inserted. */
876     protected int offset;
877     /** Length of string inserted. */
878     protected int length;
879     /** The string that was inserted. This will only be valid after an
880      * undo. */

881     protected String JavaDoc string;
882     /** An array of instances of UndoPosRef for the Positions in the
883      * range that was removed, valid after undo. */

884     protected Vector JavaDoc posRefs;
885     } // GapContent.InsertUndo
886

887
888     /**
889      * UndoableEdit created for removes.
890      */

891     class RemoveUndo extends AbstractUndoableEdit JavaDoc {
892     protected RemoveUndo(int offset, String JavaDoc 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 JavaDoc {
901         super.undo();
902         try {
903         insertString(offset, string);
904         // Update the Positions that were in the range removed.
905
if(posRefs != null) {
906             updateUndoPositions(posRefs, offset, length);
907             posRefs = null;
908         }
909         string = null;
910         } catch (BadLocationException JavaDoc bl) {
911           throw new CannotUndoException JavaDoc();
912         }
913     }
914
915     public void redo() throws CannotRedoException JavaDoc {
916         super.redo();
917         try {
918         string = getString(offset, length);
919         // Get the Positions in the range being removed.
920
posRefs = getPositionsInRange(null, offset, length);
921         remove(offset, length);
922         } catch (BadLocationException JavaDoc bl) {
923           throw new CannotRedoException JavaDoc();
924         }
925     }
926
927     /** Where the string was removed from. */
928     protected int offset;
929     /** Length of string removed. */
930     protected int length;
931     /** The string that was removed. This is valid when redo is valid. */
932     protected String JavaDoc string;
933     /** An array of instances of UndoPosRef for the Positions in the
934      * range that was removed, valid before undo. */

935     protected Vector JavaDoc posRefs;
936     } // GapContent.RemoveUndo
937
}
938
939
940
Popular Tags