1 /*
2 * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
41 * implemented using a gapped buffer similar to that used by emacs.
42 * The underlying storage is a array of unicode characters with
43 * a gap somewhere. The gap is moved to the location of changes
44 * to take advantage of common behavior where most changes are
45 * in the same location. Changes that occur at a gap boundary are
46 * generally cheap and moving the gap is generally cheaper than
47 * moving the array contents directly to accommodate the change.
48 * <p>
49 * The positions tracking change are also generally cheap to
50 * maintain. The Position implementations (marks) store the array
51 * index and can easily calculate the sequential position from
52 * the current gap location. Changes only require update to the
53 * the marks between the old and new gap boundaries when the gap
54 * is moved, so generally updating the marks is pretty cheap.
55 * The marks are stored sorted so they can be located quickly
56 * with a binary search. This increases the cost of adding a
57 * mark, and decreases the cost of keeping the mark updated.
58 *
59 * @author Timothy Prinzing
60 */
61 public class GapContent extends GapVector implements AbstractDocument.Content, Serializable {
62
63 /**
64 * Creates a new GapContent object. Initial size defaults to 10.
65 */
66 public GapContent() {
67 this(10);
68 }
69
70 /**
71 * Creates a new GapContent object, with the initial
72 * size specified. The initial size will not be allowed
73 * to go below 2, to give room for the implied break and
74 * the gap.
75 *
76 * @param initialLength the initial size
77 */
78 public GapContent(int initialLength) {
79 super(Math.max(initialLength,2));
80 char[] implied = new char[1];
560 return (cmp < 0) ? mid : mid + 1;
561 }
562
563 /**
564 * Remove all unused marks out of the sorted collection
565 * of marks.
566 */
567 final void removeUnusedMarks() {
568 int n = marks.size();
569 MarkVector cleaned = new MarkVector(n);
570 for (int i = 0; i < n; i++) {
571 MarkData mark = marks.elementAt(i);
572 if (mark.get() != null) {
573 cleaned.addElement(mark);
574 }
575 }
576 marks = cleaned;
577 unusedMarks = 0;
578 }
579
580
581 static class MarkVector extends GapVector {
582
583 MarkVector() {
584 super();
585 }
586
587 MarkVector(int size) {
588 super(size);
589 }
590
591 /**
592 * Allocate an array to store items of the type
593 * appropriate (which is determined by the subclass).
594 */
595 protected Object allocateArray(int len) {
596 return new MarkData[len];
597 }
598
599 /**
600 * Get the length of the allocated array
838 */
839 protected void resetLocation(int endOffset, int g1) {
840 if (undoLocation != endOffset) {
841 this.rec.index = undoLocation;
842 }
843 else {
844 this.rec.index = g1;
845 }
846 }
847
848 /** Previous Offset of rec. */
849 protected int undoLocation;
850 /** Mark to reset offset. */
851 protected MarkData rec;
852 } // End of GapContent.UndoPosRef
853
854
855 /**
856 * UnoableEdit created for inserts.
857 */
858 class InsertUndo extends AbstractUndoableEdit {
859 protected InsertUndo(int offset, int length) {
860 super();
861 this.offset = offset;
862 this.length = length;
863 }
864
865 public void undo() throws CannotUndoException {
866 super.undo();
867 try {
868 // Get the Positions in the range being removed.
869 posRefs = getPositionsInRange(null, offset, length);
870 string = getString(offset, length);
871 remove(offset, length);
872 } catch (BadLocationException bl) {
873 throw new CannotUndoException();
874 }
875 }
876
877 public void redo() throws CannotRedoException {
888 throw new CannotRedoException();
889 }
890 }
891
892 /** Where string was inserted. */
893 protected int offset;
894 /** Length of string inserted. */
895 protected int length;
896 /** The string that was inserted. This will only be valid after an
897 * undo. */
898 protected String string;
899 /** An array of instances of UndoPosRef for the Positions in the
900 * range that was removed, valid after undo. */
901 protected Vector posRefs;
902 } // GapContent.InsertUndo
903
904
905 /**
906 * UndoableEdit created for removes.
907 */
908 class RemoveUndo extends AbstractUndoableEdit {
909 protected RemoveUndo(int offset, String string) {
910 super();
911 this.offset = offset;
912 this.string = string;
913 this.length = string.length();
914 posRefs = getPositionsInRange(null, offset, length);
915 }
916
917 public void undo() throws CannotUndoException {
918 super.undo();
919 try {
920 insertString(offset, string);
921 // Update the Positions that were in the range removed.
922 if(posRefs != null) {
923 updateUndoPositions(posRefs, offset, length);
924 posRefs = null;
925 }
926 string = null;
927 } catch (BadLocationException bl) {
|
1 /*
2 * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
41 * implemented using a gapped buffer similar to that used by emacs.
42 * The underlying storage is a array of unicode characters with
43 * a gap somewhere. The gap is moved to the location of changes
44 * to take advantage of common behavior where most changes are
45 * in the same location. Changes that occur at a gap boundary are
46 * generally cheap and moving the gap is generally cheaper than
47 * moving the array contents directly to accommodate the change.
48 * <p>
49 * The positions tracking change are also generally cheap to
50 * maintain. The Position implementations (marks) store the array
51 * index and can easily calculate the sequential position from
52 * the current gap location. Changes only require update to the
53 * the marks between the old and new gap boundaries when the gap
54 * is moved, so generally updating the marks is pretty cheap.
55 * The marks are stored sorted so they can be located quickly
56 * with a binary search. This increases the cost of adding a
57 * mark, and decreases the cost of keeping the mark updated.
58 *
59 * @author Timothy Prinzing
60 */
61 @SuppressWarnings("serial") // Superclass is not serializable across versions
62 public class GapContent extends GapVector implements AbstractDocument.Content, Serializable {
63
64 /**
65 * Creates a new GapContent object. Initial size defaults to 10.
66 */
67 public GapContent() {
68 this(10);
69 }
70
71 /**
72 * Creates a new GapContent object, with the initial
73 * size specified. The initial size will not be allowed
74 * to go below 2, to give room for the implied break and
75 * the gap.
76 *
77 * @param initialLength the initial size
78 */
79 public GapContent(int initialLength) {
80 super(Math.max(initialLength,2));
81 char[] implied = new char[1];
561 return (cmp < 0) ? mid : mid + 1;
562 }
563
564 /**
565 * Remove all unused marks out of the sorted collection
566 * of marks.
567 */
568 final void removeUnusedMarks() {
569 int n = marks.size();
570 MarkVector cleaned = new MarkVector(n);
571 for (int i = 0; i < n; i++) {
572 MarkData mark = marks.elementAt(i);
573 if (mark.get() != null) {
574 cleaned.addElement(mark);
575 }
576 }
577 marks = cleaned;
578 unusedMarks = 0;
579 }
580
581 @SuppressWarnings("serial") // Superclass is not serializable across versions
582 static class MarkVector extends GapVector {
583
584 MarkVector() {
585 super();
586 }
587
588 MarkVector(int size) {
589 super(size);
590 }
591
592 /**
593 * Allocate an array to store items of the type
594 * appropriate (which is determined by the subclass).
595 */
596 protected Object allocateArray(int len) {
597 return new MarkData[len];
598 }
599
600 /**
601 * Get the length of the allocated array
839 */
840 protected void resetLocation(int endOffset, int g1) {
841 if (undoLocation != endOffset) {
842 this.rec.index = undoLocation;
843 }
844 else {
845 this.rec.index = g1;
846 }
847 }
848
849 /** Previous Offset of rec. */
850 protected int undoLocation;
851 /** Mark to reset offset. */
852 protected MarkData rec;
853 } // End of GapContent.UndoPosRef
854
855
856 /**
857 * UnoableEdit created for inserts.
858 */
859 @SuppressWarnings("serial") // Superclass is a JDK-implementation class
860 class InsertUndo extends AbstractUndoableEdit {
861 protected InsertUndo(int offset, int length) {
862 super();
863 this.offset = offset;
864 this.length = length;
865 }
866
867 public void undo() throws CannotUndoException {
868 super.undo();
869 try {
870 // Get the Positions in the range being removed.
871 posRefs = getPositionsInRange(null, offset, length);
872 string = getString(offset, length);
873 remove(offset, length);
874 } catch (BadLocationException bl) {
875 throw new CannotUndoException();
876 }
877 }
878
879 public void redo() throws CannotRedoException {
890 throw new CannotRedoException();
891 }
892 }
893
894 /** Where string was inserted. */
895 protected int offset;
896 /** Length of string inserted. */
897 protected int length;
898 /** The string that was inserted. This will only be valid after an
899 * undo. */
900 protected String string;
901 /** An array of instances of UndoPosRef for the Positions in the
902 * range that was removed, valid after undo. */
903 protected Vector posRefs;
904 } // GapContent.InsertUndo
905
906
907 /**
908 * UndoableEdit created for removes.
909 */
910 @SuppressWarnings("serial") // JDK-implementation class
911 class RemoveUndo extends AbstractUndoableEdit {
912 protected RemoveUndo(int offset, String string) {
913 super();
914 this.offset = offset;
915 this.string = string;
916 this.length = string.length();
917 posRefs = getPositionsInRange(null, offset, length);
918 }
919
920 public void undo() throws CannotUndoException {
921 super.undo();
922 try {
923 insertString(offset, string);
924 // Update the Positions that were in the range removed.
925 if(posRefs != null) {
926 updateUndoPositions(posRefs, offset, length);
927 posRefs = null;
928 }
929 string = null;
930 } catch (BadLocationException bl) {
|