Source Code Cross Referenced for GapContent.java in  » 6.0-JDK-Core » swing » javax » swing » text » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 1998-2003 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025        package javax.swing.text;
026
027        import java.util.Vector;
028        import java.io.IOException;
029        import java.io.ObjectInputStream;
030        import java.io.Serializable;
031        import javax.swing.undo.AbstractUndoableEdit;
032        import javax.swing.undo.CannotRedoException;
033        import javax.swing.undo.CannotUndoException;
034        import javax.swing.undo.UndoableEdit;
035        import javax.swing.SwingUtilities;
036        import java.lang.ref.WeakReference;
037        import java.lang.ref.ReferenceQueue;
038
039        /**
040         * An implementation of the AbstractDocument.Content interface 
041         * implemented using a gapped buffer similar to that used by emacs.
042         * The underlying storage is a array of unicode characters with
043         * a gap somewhere.  The gap is moved to the location of changes
044         * to take advantage of common behavior where most changes are
045         * in the same location.  Changes that occur at a gap boundary are
046         * generally cheap and moving the gap is generally cheaper than
047         * moving the array contents directly to accomodate the change.
048         * <p>
049         * The positions tracking change are also generally cheap to
050         * maintain.  The Position implementations (marks) store the array
051         * index and can easily calculate the sequential position from
052         * the current gap location.  Changes only require update to the
053         * the marks between the old and new gap boundaries when the gap
054         * is moved, so generally updating the marks is pretty cheap.
055         * The marks are stored sorted so they can be located quickly
056         * with a binary search.  This increases the cost of adding a
057         * mark, and decreases the cost of keeping the mark updated.
058         *
059         * @author  Timothy Prinzing
060         * @version 1.21 12/03/01
061         */
062        public class GapContent extends GapVector implements 
063                AbstractDocument.Content, Serializable {
064
065            /**
066             * Creates a new GapContent object.  Initial size defaults to 10.
067             */
068            public GapContent() {
069                this (10);
070            }
071
072            /**
073             * Creates a new GapContent object, with the initial
074             * size specified.  The initial size will not be allowed
075             * to go below 2, to give room for the implied break and
076             * the gap.
077             *
078             * @param initialLength the initial size
079             */
080            public GapContent(int initialLength) {
081                super (Math.max(initialLength, 2));
082                char[] implied = new char[1];
083                implied[0] = '\n';
084                replace(0, 0, implied, implied.length);
085
086                marks = new MarkVector();
087                search = new MarkData(0);
088                queue = new ReferenceQueue();
089            }
090
091            /**
092             * Allocate an array to store items of the type
093             * appropriate (which is determined by the subclass).
094             */
095            protected Object allocateArray(int len) {
096                return new char[len];
097            }
098
099            /**
100             * Get the length of the allocated array.
101             */
102            protected int getArrayLength() {
103                char[] carray = (char[]) getArray();
104                return carray.length;
105            }
106
107            // --- AbstractDocument.Content methods -------------------------
108
109            /**
110             * Returns the length of the content.
111             *
112             * @return the length >= 1
113             * @see AbstractDocument.Content#length
114             */
115            public int length() {
116                int len = getArrayLength() - (getGapEnd() - getGapStart());
117                return len;
118            }
119
120            /**
121             * Inserts a string into the content.
122             *
123             * @param where the starting position >= 0, < length()
124             * @param str the non-null string to insert
125             * @return an UndoableEdit object for undoing
126             * @exception BadLocationException if the specified position is invalid
127             * @see AbstractDocument.Content#insertString
128             */
129            public UndoableEdit insertString(int where, String str)
130                    throws BadLocationException {
131                if (where > length() || where < 0) {
132                    throw new BadLocationException("Invalid insert", length());
133                }
134                char[] chars = str.toCharArray();
135                replace(where, 0, chars, chars.length);
136                return new InsertUndo(where, str.length());
137            }
138
139            /**
140             * Removes part of the content.
141             *
142             * @param where the starting position >= 0, where + nitems < length()
143             * @param nitems the number of characters to remove >= 0
144             * @return an UndoableEdit object for undoing
145             * @exception BadLocationException if the specified position is invalid
146             * @see AbstractDocument.Content#remove
147             */
148            public UndoableEdit remove(int where, int nitems)
149                    throws BadLocationException {
150                if (where + nitems >= length()) {
151                    throw new BadLocationException("Invalid remove",
152                            length() + 1);
153                }
154                String removedString = getString(where, nitems);
155                UndoableEdit edit = new RemoveUndo(where, removedString);
156                replace(where, nitems, empty, 0);
157                return edit;
158
159            }
160
161            /**
162             * Retrieves a portion of the content.
163             *
164             * @param where the starting position >= 0
165             * @param len the length to retrieve >= 0
166             * @return a string representing the content
167             * @exception BadLocationException if the specified position is invalid
168             * @see AbstractDocument.Content#getString
169             */
170            public String getString(int where, int len)
171                    throws BadLocationException {
172                Segment s = new Segment();
173                getChars(where, len, s);
174                return new String(s.array, s.offset, s.count);
175            }
176
177            /**
178             * Retrieves a portion of the content.  If the desired content spans
179             * the gap, we copy the content.  If the desired content does not
180             * span the gap, the actual store is returned to avoid the copy since
181             * it is contiguous.
182             *
183             * @param where the starting position >= 0, where + len <= length()
184             * @param len the number of characters to retrieve >= 0
185             * @param chars the Segment object to return the characters in
186             * @exception BadLocationException if the specified position is invalid
187             * @see AbstractDocument.Content#getChars
188             */
189            public void getChars(int where, int len, Segment chars)
190                    throws BadLocationException {
191                int end = where + len;
192                if (where < 0 || end < 0) {
193                    throw new BadLocationException("Invalid location", -1);
194                }
195                if (end > length() || where > length()) {
196                    throw new BadLocationException("Invalid location",
197                            length() + 1);
198                }
199                int g0 = getGapStart();
200                int g1 = getGapEnd();
201                char[] array = (char[]) getArray();
202                if ((where + len) <= g0) {
203                    // below gap
204                    chars.array = array;
205                    chars.offset = where;
206                } else if (where >= g0) {
207                    // above gap
208                    chars.array = array;
209                    chars.offset = g1 + where - g0;
210                } else {
211                    // spans the gap
212                    int before = g0 - where;
213                    if (chars.isPartialReturn()) {
214                        // partial return allowed, return amount before the gap
215                        chars.array = array;
216                        chars.offset = where;
217                        chars.count = before;
218                        return;
219                    }
220                    // partial return not allowed, must copy
221                    chars.array = new char[len];
222                    chars.offset = 0;
223                    System.arraycopy(array, where, chars.array, 0, before);
224                    System.arraycopy(array, g1, chars.array, before, len
225                            - before);
226                }
227                chars.count = len;
228            }
229
230            /**
231             * Creates a position within the content that will
232             * track change as the content is mutated.
233             *
234             * @param offset the offset to track >= 0
235             * @return the position
236             * @exception BadLocationException if the specified position is invalid
237             */
238            public Position createPosition(int offset)
239                    throws BadLocationException {
240                while (queue.poll() != null) {
241                    unusedMarks++;
242                }
243                if (unusedMarks > Math.max(5, (marks.size() / 10))) {
244                    removeUnusedMarks();
245                }
246                int g0 = getGapStart();
247                int g1 = getGapEnd();
248                int index = (offset < g0) ? offset : offset + (g1 - g0);
249                search.index = index;
250                int sortIndex = findSortIndex(search);
251                MarkData m;
252                StickyPosition position;
253                if (sortIndex < marks.size()
254                        && (m = marks.elementAt(sortIndex)).index == index
255                        && (position = m.getPosition()) != null) {
256                    //position references the correct StickyPostition
257                } else {
258                    position = new StickyPosition();
259                    m = new MarkData(index, position, queue);
260                    position.setMark(m);
261                    marks.insertElementAt(m, sortIndex);
262                }
263
264                return position;
265            }
266
267            /**
268             * Holds the data for a mark... separately from
269             * the real mark so that the real mark (Position
270             * that the caller of createPosition holds) can be 
271             * collected if there are no more references to
272             * it.  The update table holds only a reference
273             * to this data.
274             */
275            final class MarkData extends WeakReference {
276
277                MarkData(int index) {
278                    super (null);
279                    this .index = index;
280                }
281
282                MarkData(int index, StickyPosition position,
283                        ReferenceQueue queue) {
284                    super (position, queue);
285                    this .index = index;
286                }
287
288                /**
289                 * Fetch the location in the contiguous sequence
290                 * being modeled.  The index in the gap array
291                 * is held by the mark, so it is adjusted according
292                 * to it's relationship to the gap.
293                 */
294                public final int getOffset() {
295                    int g0 = getGapStart();
296                    int g1 = getGapEnd();
297                    int offs = (index < g0) ? index : index - (g1 - g0);
298                    return Math.max(offs, 0);
299                }
300
301                StickyPosition getPosition() {
302                    return (StickyPosition) get();
303                }
304
305                int index;
306            }
307
308            final class StickyPosition implements  Position {
309
310                StickyPosition() {
311                }
312
313                void setMark(MarkData mark) {
314                    this .mark = mark;
315                }
316
317                public final int getOffset() {
318                    return mark.getOffset();
319                }
320
321                public String toString() {
322                    return Integer.toString(getOffset());
323                }
324
325                MarkData mark;
326            }
327
328            // --- variables --------------------------------------
329
330            private static final char[] empty = new char[0];
331            private transient MarkVector marks;
332
333            /**
334             * Record used for searching for the place to
335             * start updating mark indexs when the gap 
336             * boundaries are moved.
337             */
338            private transient MarkData search;
339
340            /**
341             * The number of unused mark entries
342             */
343            private transient int unusedMarks = 0;
344
345            private transient ReferenceQueue queue;
346
347            final static int GROWTH_SIZE = 1024 * 512;
348
349            // --- gap management -------------------------------
350
351            /**
352             * Make the gap bigger, moving any necessary data and updating 
353             * the appropriate marks
354             */
355            protected void shiftEnd(int newSize) {
356                int oldGapEnd = getGapEnd();
357
358                super .shiftEnd(newSize);
359
360                // Adjust marks.
361                int dg = getGapEnd() - oldGapEnd;
362                int adjustIndex = findMarkAdjustIndex(oldGapEnd);
363                int n = marks.size();
364                for (int i = adjustIndex; i < n; i++) {
365                    MarkData mark = marks.elementAt(i);
366                    mark.index += dg;
367                }
368            }
369
370            /**
371             * Overridden to make growth policy less agressive for large
372             * text amount.
373             */
374            int getNewArraySize(int reqSize) {
375                if (reqSize < GROWTH_SIZE) {
376                    return super .getNewArraySize(reqSize);
377                } else {
378                    return reqSize + GROWTH_SIZE;
379                }
380            }
381
382            /**
383             * Move the start of the gap to a new location,
384             * without changing the size of the gap.  This 
385             * moves the data in the array and updates the
386             * marks accordingly.
387             */
388            protected void shiftGap(int newGapStart) {
389                int oldGapStart = getGapStart();
390                int dg = newGapStart - oldGapStart;
391                int oldGapEnd = getGapEnd();
392                int newGapEnd = oldGapEnd + dg;
393                int gapSize = oldGapEnd - oldGapStart;
394
395                // shift gap in the character array
396                super .shiftGap(newGapStart);
397
398                // update the marks
399                if (dg > 0) {
400                    // Move gap up, move data and marks down.
401                    int adjustIndex = findMarkAdjustIndex(oldGapStart);
402                    int n = marks.size();
403                    for (int i = adjustIndex; i < n; i++) {
404                        MarkData mark = marks.elementAt(i);
405                        if (mark.index >= newGapEnd) {
406                            break;
407                        }
408                        mark.index -= gapSize;
409                    }
410                } else if (dg < 0) {
411                    // Move gap down, move data and marks up.
412                    int adjustIndex = findMarkAdjustIndex(newGapStart);
413                    int n = marks.size();
414                    for (int i = adjustIndex; i < n; i++) {
415                        MarkData mark = marks.elementAt(i);
416                        if (mark.index >= oldGapEnd) {
417                            break;
418                        }
419                        mark.index += gapSize;
420                    }
421                }
422                resetMarksAtZero();
423            }
424
425            /**
426             * Resets all the marks that have an offset of 0 to have an index of
427             * zero as well.
428             */
429            protected void resetMarksAtZero() {
430                if (marks != null && getGapStart() == 0) {
431                    int g1 = getGapEnd();
432                    for (int counter = 0, maxCounter = marks.size(); counter < maxCounter; counter++) {
433                        MarkData mark = marks.elementAt(counter);
434                        if (mark.index <= g1) {
435                            mark.index = 0;
436                        } else {
437                            break;
438                        }
439                    }
440                }
441            }
442
443            /**
444             * Adjust the gap end downward.  This doesn't move
445             * any data, but it does update any marks affected 
446             * by the boundary change.  All marks from the old
447             * gap start down to the new gap start are squeezed
448             * to the end of the gap (their location has been
449             * removed).
450             */
451            protected void shiftGapStartDown(int newGapStart) {
452                // Push aside all marks from oldGapStart down to newGapStart.
453                int adjustIndex = findMarkAdjustIndex(newGapStart);
454                int n = marks.size();
455                int g0 = getGapStart();
456                int g1 = getGapEnd();
457                for (int i = adjustIndex; i < n; i++) {
458                    MarkData mark = marks.elementAt(i);
459                    if (mark.index > g0) {
460                        // no more marks to adjust
461                        break;
462                    }
463                    mark.index = g1;
464                }
465
466                // shift the gap in the character array
467                super .shiftGapStartDown(newGapStart);
468
469                resetMarksAtZero();
470            }
471
472            /**
473             * Adjust the gap end upward.  This doesn't move
474             * any data, but it does update any marks affected 
475             * by the boundary change. All marks from the old
476             * gap end up to the new gap end are squeezed
477             * to the end of the gap (their location has been
478             * removed).
479             */
480            protected void shiftGapEndUp(int newGapEnd) {
481                int adjustIndex = findMarkAdjustIndex(getGapEnd());
482                int n = marks.size();
483                for (int i = adjustIndex; i < n; i++) {
484                    MarkData mark = marks.elementAt(i);
485                    if (mark.index >= newGapEnd) {
486                        break;
487                    }
488                    mark.index = newGapEnd;
489                }
490
491                // shift the gap in the character array
492                super .shiftGapEndUp(newGapEnd);
493
494                resetMarksAtZero();
495            }
496
497            /**
498             * Compares two marks.
499             *
500             * @param o1 the first object
501             * @param o2 the second object
502             * @return < 0 if o1 < o2, 0 if the same, > 0 if o1 > o2
503             */
504            final int compare(MarkData o1, MarkData o2) {
505                if (o1.index < o2.index) {
506                    return -1;
507                } else if (o1.index > o2.index) {
508                    return 1;
509                } else {
510                    return 0;
511                }
512            }
513
514            /**
515             * Finds the index to start mark adjustments given
516             * some search index.
517             */
518            final int findMarkAdjustIndex(int searchIndex) {
519                search.index = Math.max(searchIndex, 1);
520                int index = findSortIndex(search);
521
522                // return the first in the series
523                // (ie. there may be duplicates).
524                for (int i = index - 1; i >= 0; i--) {
525                    MarkData d = marks.elementAt(i);
526                    if (d.index != search.index) {
527                        break;
528                    }
529                    index -= 1;
530                }
531                return index;
532            }
533
534            /**
535             * Finds the index of where to insert a new mark.
536             *
537             * @param o the mark to insert
538             * @return the index
539             */
540            final int findSortIndex(MarkData o) {
541                int lower = 0;
542                int upper = marks.size() - 1;
543                int mid = 0;
544
545                if (upper == -1) {
546                    return 0;
547                }
548
549                int cmp = 0;
550                MarkData last = marks.elementAt(upper);
551                cmp = compare(o, last);
552                if (cmp > 0)
553                    return upper + 1;
554
555                while (lower <= upper) {
556                    mid = lower + ((upper - lower) / 2);
557                    MarkData entry = marks.elementAt(mid);
558                    cmp = compare(o, entry);
559
560                    if (cmp == 0) {
561                        // found a match
562                        return mid;
563                    } else if (cmp < 0) {
564                        upper = mid - 1;
565                    } else {
566                        lower = mid + 1;
567                    }
568                }
569
570                // didn't find it, but we indicate the index of where it would belong.
571                return (cmp < 0) ? mid : mid + 1;
572            }
573
574            /**
575             * Remove all unused marks out of the sorted collection
576             * of marks.  
577             */
578            final void removeUnusedMarks() {
579                int n = marks.size();
580                MarkVector cleaned = new MarkVector(n);
581                for (int i = 0; i < n; i++) {
582                    MarkData mark = marks.elementAt(i);
583                    if (mark.get() != null) {
584                        cleaned.addElement(mark);
585                    }
586                }
587                marks = cleaned;
588                unusedMarks = 0;
589            }
590
591            static class MarkVector extends GapVector {
592
593                MarkVector() {
594                    super ();
595                }
596
597                MarkVector(int size) {
598                    super (size);
599                }
600
601                /**
602                 * Allocate an array to store items of the type
603                 * appropriate (which is determined by the subclass).
604                 */
605                protected Object allocateArray(int len) {
606                    return new MarkData[len];
607                }
608
609                /**
610                 * Get the length of the allocated array
611                 */
612                protected int getArrayLength() {
613                    MarkData[] marks = (MarkData[]) getArray();
614                    return marks.length;
615                }
616
617                /**
618                 * Returns the number of marks currently held
619                 */
620                public int size() {
621                    int len = getArrayLength() - (getGapEnd() - getGapStart());
622                    return len;
623                }
624
625                /**
626                 * Inserts a mark into the vector
627                 */
628                public void insertElementAt(MarkData m, int index) {
629                    oneMark[0] = m;
630                    replace(index, 0, oneMark, 1);
631                }
632
633                /**
634                 * Add a mark to the end
635                 */
636                public void addElement(MarkData m) {
637                    insertElementAt(m, size());
638                }
639
640                /**
641                 * Fetches the mark at the given index
642                 */
643                public MarkData elementAt(int index) {
644                    int g0 = getGapStart();
645                    int g1 = getGapEnd();
646                    MarkData[] array = (MarkData[]) getArray();
647                    if (index < g0) {
648                        // below gap
649                        return array[index];
650                    } else {
651                        // above gap
652                        index += g1 - g0;
653                        return array[index];
654                    }
655                }
656
657                /**
658                 * Replaces the elements in the specified range with the passed
659                 * in objects. This will NOT adjust the gap. The passed in indices
660                 * do not account for the gap, they are the same as would be used
661                 * int <code>elementAt</code>.
662                 */
663                protected void replaceRange(int start, int end, Object[] marks) {
664                    int g0 = getGapStart();
665                    int g1 = getGapEnd();
666                    int index = start;
667                    int newIndex = 0;
668                    Object[] array = (Object[]) getArray();
669                    if (start >= g0) {
670                        // Completely passed gap
671                        index += (g1 - g0);
672                        end += (g1 - g0);
673                    } else if (end >= g0) {
674                        // straddles gap
675                        end += (g1 - g0);
676                        while (index < g0) {
677                            array[index++] = marks[newIndex++];
678                        }
679                        index = g1;
680                    } else {
681                        // below gap
682                        while (index < end) {
683                            array[index++] = marks[newIndex++];
684                        }
685                    }
686                    while (index < end) {
687                        array[index++] = marks[newIndex++];
688                    }
689                }
690
691                MarkData[] oneMark = new MarkData[1];
692
693            }
694
695            // --- serialization -------------------------------------
696
697            private void readObject(ObjectInputStream s)
698                    throws ClassNotFoundException, IOException {
699                s.defaultReadObject();
700                marks = new MarkVector();
701                search = new MarkData(0);
702                queue = new ReferenceQueue();
703            }
704
705            // --- undo support --------------------------------------
706
707            /**
708             * Returns a Vector containing instances of UndoPosRef for the
709             * Positions in the range
710             * <code>offset</code> to <code>offset</code> + <code>length</code>.
711             * If <code>v</code> is not null the matching Positions are placed in
712             * there. The vector with the resulting Positions are returned.
713             *
714             * @param v the Vector to use, with a new one created on null
715             * @param offset the starting offset >= 0
716             * @param length the length >= 0
717             * @return the set of instances
718             */
719            protected Vector getPositionsInRange(Vector v, int offset,
720                    int length) {
721                int endOffset = offset + length;
722                int startIndex;
723                int endIndex;
724                int g0 = getGapStart();
725                int g1 = getGapEnd();
726
727                // Find the index of the marks.
728                if (offset < g0) {
729                    if (offset == 0) {
730                        // findMarkAdjustIndex start at 1!
731                        startIndex = 0;
732                    } else {
733                        startIndex = findMarkAdjustIndex(offset);
734                    }
735                    if (endOffset >= g0) {
736                        endIndex = findMarkAdjustIndex(endOffset + (g1 - g0)
737                                + 1);
738                    } else {
739                        endIndex = findMarkAdjustIndex(endOffset + 1);
740                    }
741                } else {
742                    startIndex = findMarkAdjustIndex(offset + (g1 - g0));
743                    endIndex = findMarkAdjustIndex(endOffset + (g1 - g0) + 1);
744                }
745
746                Vector placeIn = (v == null) ? new Vector(Math.max(1, endIndex
747                        - startIndex)) : v;
748
749                for (int counter = startIndex; counter < endIndex; counter++) {
750                    placeIn
751                            .addElement(new UndoPosRef(marks.elementAt(counter)));
752                }
753                return placeIn;
754            }
755
756            /**
757             * Resets the location for all the UndoPosRef instances
758             * in <code>positions</code>.
759             * <p>
760             * This is meant for internal usage, and is generally not of interest
761             * to subclasses.
762             *
763             * @param positions the UndoPosRef instances to reset
764             */
765            protected void updateUndoPositions(Vector positions, int offset,
766                    int length) {
767                // Find the indexs of the end points.
768                int endOffset = offset + length;
769                int g1 = getGapEnd();
770                int startIndex;
771                int endIndex = findMarkAdjustIndex(g1 + 1);
772
773                if (offset != 0) {
774                    startIndex = findMarkAdjustIndex(g1);
775                } else {
776                    startIndex = 0;
777                }
778
779                // Reset the location of the refenences.
780                for (int counter = positions.size() - 1; counter >= 0; counter--) {
781                    UndoPosRef ref = (UndoPosRef) positions.elementAt(counter);
782                    ref.resetLocation(endOffset, g1);
783                }
784                // We have to resort the marks in the range startIndex to endIndex.
785                // We can take advantage of the fact that it will be in
786                // increasing order, accept there will be a bunch of MarkData's with
787                // the index g1 (or 0 if offset == 0) interspersed throughout.
788                if (startIndex < endIndex) {
789                    Object[] sorted = new Object[endIndex - startIndex];
790                    int addIndex = 0;
791                    int counter;
792                    if (offset == 0) {
793                        // If the offset is 0, the positions won't have incremented,
794                        // have to do the reverse thing.
795                        // Find the elements in startIndex whose index is 0
796                        for (counter = startIndex; counter < endIndex; counter++) {
797                            MarkData mark = marks.elementAt(counter);
798                            if (mark.index == 0) {
799                                sorted[addIndex++] = mark;
800                            }
801                        }
802                        for (counter = startIndex; counter < endIndex; counter++) {
803                            MarkData mark = marks.elementAt(counter);
804                            if (mark.index != 0) {
805                                sorted[addIndex++] = mark;
806                            }
807                        }
808                    } else {
809                        for (counter = startIndex; counter < endIndex; counter++) {
810                            MarkData mark = marks.elementAt(counter);
811                            if (mark.index != g1) {
812                                sorted[addIndex++] = mark;
813                            }
814                        }
815                        for (counter = startIndex; counter < endIndex; counter++) {
816                            MarkData mark = marks.elementAt(counter);
817                            if (mark.index == g1) {
818                                sorted[addIndex++] = mark;
819                            }
820                        }
821                    }
822                    // And replace
823                    marks.replaceRange(startIndex, endIndex, sorted);
824                }
825            }
826
827            /**
828             * Used to hold a reference to a Mark that is being reset as the
829             * result of removing from the content.
830             */
831            final class UndoPosRef {
832                UndoPosRef(MarkData rec) {
833                    this .rec = rec;
834                    this .undoLocation = rec.getOffset();
835                }
836
837                /**
838                 * Resets the location of the Position to the offset when the
839                 * receiver was instantiated.
840                 *
841                 * @param endOffset end location of inserted string.
842                 * @param g1 resulting end of gap.
843                 */
844                protected void resetLocation(int endOffset, int g1) {
845                    if (undoLocation != endOffset) {
846                        this .rec.index = undoLocation;
847                    } else {
848                        this .rec.index = g1;
849                    }
850                }
851
852                /** Previous Offset of rec. */
853                protected int undoLocation;
854                /** Mark to reset offset. */
855                protected MarkData rec;
856            } // End of GapContent.UndoPosRef
857
858            /**
859             * UnoableEdit created for inserts.
860             */
861            class InsertUndo extends AbstractUndoableEdit {
862                protected InsertUndo(int offset, int length) {
863                    super ();
864                    this .offset = offset;
865                    this .length = length;
866                }
867
868                public void undo() throws CannotUndoException {
869                    super .undo();
870                    try {
871                        // Get the Positions in the range being removed.
872                        posRefs = getPositionsInRange(null, offset, length);
873                        string = getString(offset, length);
874                        remove(offset, length);
875                    } catch (BadLocationException bl) {
876                        throw new CannotUndoException();
877                    }
878                }
879
880                public void redo() throws CannotRedoException {
881                    super .redo();
882                    try {
883                        insertString(offset, string);
884                        string = null;
885                        // Update the Positions that were in the range removed.
886                        if (posRefs != null) {
887                            updateUndoPositions(posRefs, offset, length);
888                            posRefs = null;
889                        }
890                    } catch (BadLocationException bl) {
891                        throw new CannotRedoException();
892                    }
893                }
894
895                /** Where string was inserted. */
896                protected int offset;
897                /** Length of string inserted. */
898                protected int length;
899                /** The string that was inserted. This will only be valid after an
900                 * undo. */
901                protected String string;
902                /** An array of instances of UndoPosRef for the Positions in the
903                 * range that was removed, valid after undo. */
904                protected Vector posRefs;
905            } // GapContent.InsertUndo
906
907            /**
908             * UndoableEdit created for removes.
909             */
910            class RemoveUndo extends AbstractUndoableEdit {
911                protected RemoveUndo(int offset, String string) {
912                    super ();
913                    this .offset = offset;
914                    this .string = string;
915                    this .length = string.length();
916                    posRefs = getPositionsInRange(null, offset, length);
917                }
918
919                public void undo() throws CannotUndoException {
920                    super .undo();
921                    try {
922                        insertString(offset, string);
923                        // Update the Positions that were in the range removed.
924                        if (posRefs != null) {
925                            updateUndoPositions(posRefs, offset, length);
926                            posRefs = null;
927                        }
928                        string = null;
929                    } catch (BadLocationException bl) {
930                        throw new CannotUndoException();
931                    }
932                }
933
934                public void redo() throws CannotRedoException {
935                    super .redo();
936                    try {
937                        string = getString(offset, length);
938                        // Get the Positions in the range being removed.
939                        posRefs = getPositionsInRange(null, offset, length);
940                        remove(offset, length);
941                    } catch (BadLocationException bl) {
942                        throw new CannotRedoException();
943                    }
944                }
945
946                /** Where the string was removed from. */
947                protected int offset;
948                /** Length of string removed. */
949                protected int length;
950                /** The string that was removed. This is valid when redo is valid. */
951                protected String string;
952                /** An array of instances of UndoPosRef for the Positions in the
953                 * range that was removed, valid before undo. */
954                protected Vector posRefs;
955            } // GapContent.RemoveUndo
956        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.