/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* An implementation of the AbstractDocument.Content interface
* implemented using a gapped buffer similar to that used by emacs.
* The underlying storage is a array of unicode characters with
* a gap somewhere. The gap is moved to the location of changes
* to take advantage of common behavior where most changes are
* in the same location. Changes that occur at a gap boundary are
* generally cheap and moving the gap is generally cheaper than
* moving the array contents directly to accomodate the change.
* <p>
* The positions tracking change are also generally cheap to
* maintain. The Position implementations (marks) store the array
* index and can easily calculate the sequential position from
* the current gap location. Changes only require update to the
* the marks between the old and new gap boundaries when the gap
* is moved, so generally updating the marks is pretty cheap.
* The marks are stored sorted so they can be located quickly
* with a binary search. This increases the cost of adding a
* mark, and decreases the cost of keeping the mark updated.
*
* @author Timothy Prinzing
*/
/**
* Creates a new GapContent object. Initial size defaults to 10.
*/
public GapContent() {
this(10);
}
/**
* Creates a new GapContent object, with the initial
* size specified. The initial size will not be allowed
* to go below 2, to give room for the implied break and
* the gap.
*
* @param initialLength the initial size
*/
char[] implied = new char[1];
marks = new MarkVector();
}
/**
* Allocate an array to store items of the type
* appropriate (which is determined by the subclass).
*/
return new char[len];
}
/**
* Get the length of the allocated array.
*/
protected int getArrayLength() {
}
// --- AbstractDocument.Content methods -------------------------
/**
* Returns the length of the content.
*
* @return the length >= 1
* @see AbstractDocument.Content#length
*/
public int length() {
return len;
}
/**
* Inserts a string into the content.
*
* @param where the starting position >= 0, < length()
* @param str the non-null string to insert
* @return an UndoableEdit object for undoing
* @exception BadLocationException if the specified position is invalid
* @see AbstractDocument.Content#insertString
*/
}
}
/**
* Removes part of the content.
*
* @param where the starting position >= 0, where + nitems < length()
* @param nitems the number of characters to remove >= 0
* @return an UndoableEdit object for undoing
* @exception BadLocationException if the specified position is invalid
* @see AbstractDocument.Content#remove
*/
}
return edit;
}
/**
* Retrieves a portion of the content.
*
* @param where the starting position >= 0
* @param len the length to retrieve >= 0
* @return a string representing the content
* @exception BadLocationException if the specified position is invalid
* @see AbstractDocument.Content#getString
*/
}
/**
* Retrieves a portion of the content. If the desired content spans
* the gap, we copy the content. If the desired content does not
* span the gap, the actual store is returned to avoid the copy since
* it is contiguous.
*
* @param where the starting position >= 0, where + len <= length()
* @param len the number of characters to retrieve >= 0
* @param chars the Segment object to return the characters in
* @exception BadLocationException if the specified position is invalid
* @see AbstractDocument.Content#getChars
*/
}
}
int g0 = getGapStart();
// below gap
// above gap
} else {
// spans the gap
if (chars.isPartialReturn()) {
// partial return allowed, return amount before the gap
return;
}
// partial return not allowed, must copy
}
}
/**
* Creates a position within the content that will
* track change as the content is mutated.
*
* @param offset the offset to track >= 0
* @return the position
* @exception BadLocationException if the specified position is invalid
*/
unusedMarks++;
}
}
int g0 = getGapStart();
MarkData m;
//position references the correct StickyPostition
} else {
position = new StickyPosition();
}
return position;
}
/**
* Holds the data for a mark... separately from
* the real mark so that the real mark (Position
* that the caller of createPosition holds) can be
* collected if there are no more references to
* it. The update table holds only a reference
* to this data.
*/
super(null);
}
}
/**
* Fetch the location in the contiguous sequence
* being modeled. The index in the gap array
* is held by the mark, so it is adjusted according
* to it's relationship to the gap.
*/
public final int getOffset() {
int g0 = getGapStart();
}
return get();
}
int index;
}
StickyPosition() {
}
}
public final int getOffset() {
}
}
}
// --- variables --------------------------------------
/**
* Record used for searching for the place to
* start updating mark indexs when the gap
* boundaries are moved.
*/
/**
* The number of unused mark entries
*/
// --- gap management -------------------------------
/**
* Make the gap bigger, moving any necessary data and updating
* the appropriate marks
*/
// Adjust marks.
for (int i = adjustIndex; i < n; i++) {
}
}
/**
* Overridden to make growth policy less agressive for large
* text amount.
*/
if (reqSize < GROWTH_SIZE) {
return super.getNewArraySize(reqSize);
} else {
return reqSize + GROWTH_SIZE;
}
}
/**
* Move the start of the gap to a new location,
* without changing the size of the gap. This
* moves the data in the array and updates the
* marks accordingly.
*/
int oldGapStart = getGapStart();
// shift gap in the character array
super.shiftGap(newGapStart);
// update the marks
if (dg > 0) {
// Move gap up, move data and marks down.
for (int i = adjustIndex; i < n; i++) {
break;
}
}
} else if (dg < 0) {
// Move gap down, move data and marks up.
for (int i = adjustIndex; i < n; i++) {
break;
}
}
}
}
/**
* Resets all the marks that have an offset of 0 to have an index of
* zero as well.
*/
protected void resetMarksAtZero() {
}
else {
break;
}
}
}
}
/**
* Adjust the gap end downward. This doesn't move
* any data, but it does update any marks affected
* by the boundary change. All marks from the old
* gap start down to the new gap start are squeezed
* to the end of the gap (their location has been
* removed).
*/
// Push aside all marks from oldGapStart down to newGapStart.
int g0 = getGapStart();
for (int i = adjustIndex; i < n; i++) {
// no more marks to adjust
break;
}
}
// shift the gap in the character array
super.shiftGapStartDown(newGapStart);
}
/**
* Adjust the gap end upward. This doesn't move
* any data, but it does update any marks affected
* by the boundary change. All marks from the old
* gap end up to the new gap end are squeezed
* to the end of the gap (their location has been
* removed).
*/
for (int i = adjustIndex; i < n; i++) {
break;
}
}
// shift the gap in the character array
super.shiftGapEndUp(newGapEnd);
}
/**
* Compares two marks.
*
* @param o1 the first object
* @param o2 the second object
* @return < 0 if o1 < o2, 0 if the same, > 0 if o1 > o2
*/
return -1;
return 1;
} else {
return 0;
}
}
/**
* Finds the index to start mark adjustments given
* some search index.
*/
// return the first in the series
// (ie. there may be duplicates).
break;
}
index -= 1;
}
return index;
}
/**
* Finds the index of where to insert a new mark.
*
* @param o the mark to insert
* @return the index
*/
int lower = 0;
int mid = 0;
if (upper == -1) {
return 0;
}
int cmp;
if (cmp > 0)
return upper + 1;
if (cmp == 0) {
// found a match
return mid;
} else if (cmp < 0) {
} else {
}
}
// didn't find it, but we indicate the index of where it would belong.
}
/**
* Remove all unused marks out of the sorted collection
* of marks.
*/
final void removeUnusedMarks() {
for (int i = 0; i < n; i++) {
}
}
unusedMarks = 0;
}
MarkVector() {
super();
}
super(size);
}
/**
* Allocate an array to store items of the type
* appropriate (which is determined by the subclass).
*/
}
/**
* Get the length of the allocated array
*/
protected int getArrayLength() {
}
/**
* Returns the number of marks currently held
*/
public int size() {
return len;
}
/**
* Inserts a mark into the vector
*/
oneMark[0] = m;
}
/**
* Add a mark to the end
*/
insertElementAt(m, size());
}
/**
* Fetches the mark at the given index
*/
int g0 = getGapStart();
// below gap
} else {
// above gap
}
}
/**
* Replaces the elements in the specified range with the passed
* in objects. This will NOT adjust the gap. The passed in indices
* do not account for the gap, they are the same as would be used
* int <code>elementAt</code>.
*/
int g0 = getGapStart();
int newIndex = 0;
// Completely passed gap
}
// straddles gap
}
}
else {
// below gap
}
}
}
}
}
// --- serialization -------------------------------------
throws ClassNotFoundException, IOException {
s.defaultReadObject();
marks = new MarkVector();
}
// --- undo support --------------------------------------
/**
* Returns a Vector containing instances of UndoPosRef for the
* Positions in the range
* <code>offset</code> to <code>offset</code> + <code>length</code>.
* If <code>v</code> is not null the matching Positions are placed in
* there. The vector with the resulting Positions are returned.
*
* @param v the Vector to use, with a new one created on null
* @param offset the starting offset >= 0
* @param length the length >= 0
* @return the set of instances
*/
int startIndex;
int endIndex;
int g0 = getGapStart();
// Find the index of the marks.
if (offset == 0) {
// findMarkAdjustIndex start at 1!
startIndex = 0;
}
else {
}
}
else {
}
}
else {
}
startIndex)) : v;
}
return placeIn;
}
/**
* Resets the location for all the UndoPosRef instances
* in <code>positions</code>.
* <p>
* This is meant for internal usage, and is generally not of interest
* to subclasses.
*
* @param positions the UndoPosRef instances to reset
*/
int length) {
// Find the indexs of the end points.
int startIndex;
if (offset != 0) {
}
else {
startIndex = 0;
}
// Reset the location of the refenences.
}
// We have to resort the marks in the range startIndex to endIndex.
// We can take advantage of the fact that it will be in
// increasing order, accept there will be a bunch of MarkData's with
// the index g1 (or 0 if offset == 0) interspersed throughout.
if (startIndex < endIndex) {
int addIndex = 0;
int counter;
if (offset == 0) {
// If the offset is 0, the positions won't have incremented,
// have to do the reverse thing.
// Find the elements in startIndex whose index is 0
}
}
}
}
}
else {
}
}
}
}
}
// And replace
}
}
/**
* Used to hold a reference to a Mark that is being reset as the
* result of removing from the content.
*/
final class UndoPosRef {
}
/**
* Resets the location of the Position to the offset when the
* receiver was instantiated.
*
* @param endOffset end location of inserted string.
* @param g1 resulting end of gap.
*/
if (undoLocation != endOffset) {
}
else {
}
}
/** Previous Offset of rec. */
protected int undoLocation;
/** Mark to reset offset. */
} // End of GapContent.UndoPosRef
/**
* UnoableEdit created for inserts.
*/
super();
}
super.undo();
try {
// Get the Positions in the range being removed.
} catch (BadLocationException bl) {
throw new CannotUndoException();
}
}
super.redo();
try {
// Update the Positions that were in the range removed.
}
} catch (BadLocationException bl) {
throw new CannotRedoException();
}
}
/** Where string was inserted. */
protected int offset;
/** Length of string inserted. */
protected int length;
/** The string that was inserted. This will only be valid after an
* undo. */
/** An array of instances of UndoPosRef for the Positions in the
* range that was removed, valid after undo. */
} // GapContent.InsertUndo
/**
* UndoableEdit created for removes.
*/
super();
}
super.undo();
try {
// Update the Positions that were in the range removed.
}
} catch (BadLocationException bl) {
throw new CannotUndoException();
}
}
super.redo();
try {
// Get the Positions in the range being removed.
} catch (BadLocationException bl) {
throw new CannotRedoException();
}
}
/** Where the string was removed from. */
protected int offset;
/** Length of string removed. */
protected int length;
/** The string that was removed. This is valid when redo is valid. */
/** An array of instances of UndoPosRef for the Positions in the
* range that was removed, valid before undo. */
} // GapContent.RemoveUndo
}