This fixes Undo/Redo support in GapContent. We need to reset all the
positions in removed text areas after an undo/redo. The implementation
is tested against Intel's testsuite (we now pass all the tests in
Intel's and Mauve suite for GapContent :-D).
2006-08-11 Roman Kennke <[EMAIL PROTECTED]>
* javax/swing/text/GapContent.java
(UndoPosRef): New inner class. Used for resetting positions
after undo/redo operations.
(InsertUndo.positions): New field.
(InsertUndo.undo): Store positions in removed range.
(InsertUndo.redo): Restore positions in re-inserted range.
(UndoRemove.positions): New field.
(UndoRemove.UndoRemove): Store positions in removed range.
(UndoRemove.undo): Restore positions in re-inserted range.
(UndoRemove.redo): Store positions in removed range.
(insertString): Create InsertUndo instance before actually
inserting the string.
(remove): Create UndoRemove instance before actually
removing.
(getPositionsInRange): Don't clear the Vector. Return Vector
of UndoPosRefs.
(updateUndoPositions): Implemented to reset all UndoPosRefs
in the vector.
/Roman
Index: javax/swing/text/GapContent.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/GapContent.java,v
retrieving revision 1.55
diff -u -1 -2 -r1.55 GapContent.java
--- javax/swing/text/GapContent.java 10 Aug 2006 21:21:40 -0000 1.55
+++ javax/swing/text/GapContent.java 11 Aug 2006 11:15:30 -0000
@@ -186,97 +186,156 @@
/**
* Adjustment for equals().
*/
public boolean equals(Object o)
{
if (o == null || !(o instanceof Mark))
return false;
else
return ((Mark) o).mark == mark;
}
}
+ /**
+ * Stores a reference to a mark that can be resetted to the original value
+ * after a mark has been moved. This is used for undoing actions.
+ */
+ private class UndoPosRef
+ {
+ /**
+ * The mark that might need to be reset.
+ */
+ private Mark mark;
+
+ /**
+ * The original offset to reset the mark to.
+ */
+ private int undoOffset;
+
+ /**
+ * Creates a new UndoPosRef.
+ *
+ * @param m the mark
+ */
+ UndoPosRef(Mark m)
+ {
+ mark = m;
+ undoOffset = mark.getOffset();
+ }
+
+ /**
+ * Resets the position of the mark to the value that it had when
+ * creating this UndoPosRef.
+ */
+ void reset()
+ {
+ if (undoOffset <= gapStart)
+ mark.mark = undoOffset;
+ else
+ mark.mark = (gapEnd - gapStart) + undoOffset;
+ }
+ }
+
private class InsertUndo extends AbstractUndoableEdit
{
public int where, length;
String text;
+ private Vector positions;
+
public InsertUndo(int start, int len)
{
where = start;
length = len;
}
public void undo () throws CannotUndoException
{
super.undo();
try
- {
- text = getString(where, length);
- remove(where, length);
- }
+ {
+ positions = getPositionsInRange(null, where, length);
+ text = getString(where, length);
+ remove(where, length);
+ }
catch (BadLocationException ble)
- {
- throw new CannotUndoException();
- }
+ {
+ throw new CannotUndoException();
+ }
}
public void redo () throws CannotUndoException
{
super.redo();
try
- {
- insertString(where, text);
- }
+ {
+ insertString(where, text);
+ if (positions != null)
+ {
+ updateUndoPositions(positions, where, length);
+ positions = null;
+ }
+ }
catch (BadLocationException ble)
- {
- throw new CannotRedoException();
- }
+ {
+ throw new CannotRedoException();
+ }
}
}
private class UndoRemove extends AbstractUndoableEdit
{
public int where;
String text;
+
+ /**
+ * The positions in the removed range.
+ */
+ private Vector positions;
+
public UndoRemove(int start, String removedText)
{
where = start;
text = removedText;
+ positions = getPositionsInRange(null, start, removedText.length());
}
public void undo () throws CannotUndoException
{
super.undo();
try
{
insertString(where, text);
+ if (positions != null)
+ updateUndoPositions(positions, where, text.length());
}
catch (BadLocationException ble)
{
throw new CannotUndoException();
}
}
public void redo () throws CannotUndoException
{
super.redo();
try
- {
- remove(where, text.length());
- }
+ {
+ text = getString(where, text.length());
+ positions = getPositionsInRange(null, where, text.length());
+ remove(where, text.length());
+ }
catch (BadLocationException ble)
- {
- throw new CannotRedoException();
- }
+ {
+ throw new CannotRedoException();
+ }
}
}
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = -6226052713477823730L;
/**
* This is the default buffer size and the amount of bytes that a buffer is
* extended if it is full.
*/
static final int DEFAULT_BUFSIZE = 10;
@@ -394,53 +453,55 @@
// check arguments
int length = length();
int strLen = str.length();
if (where < 0)
throw new BadLocationException("The where argument cannot be smaller"
+ " than the zero", where);
if (where > length)
throw new BadLocationException("The where argument cannot be greater"
+ " than the content length", where);
+ InsertUndo undo = new InsertUndo(where, strLen);
replace(where, 0, str.toCharArray(), strLen);
- return new InsertUndo(where, strLen);
+ return undo;
}
/**
* Removes a piece of content at th specified position.
*
* @param where the position where the content is to be removed
* @param nitems number of characters to be removed
*
* @return an UndoableEdit object
*
* @throws BadLocationException if <code>where</code> is not a valid
* location in the buffer
*/
public UndoableEdit remove(int where, int nitems) throws BadLocationException
{
// check arguments
int length = length();
if ((where + nitems) >= length)
throw new BadLocationException("where + nitems cannot be greater"
+ " than the content length", where + nitems);
String removedText = getString(where, nitems);
+ UndoRemove undoRemove = new UndoRemove(where, removedText);
replace(where, nitems, null, 0);
- return new UndoRemove(where, removedText);
+ return undoRemove;
}
/**
* Returns a piece of content as String.
*
* @param where the start location of the fragment
* @param len the length of the fragment
*
* @throws BadLocationException if <code>where</code> or
* <code>where + len</code> are no valid locations in the buffer
*/
public String getString(int where, int len) throws BadLocationException
@@ -741,36 +802,34 @@
*
* @param v the vector to use; if <code>null</code>, a new Vector is allocated
* @param offset the start offset of the range to search
* @param length the length of the range to search
*
* @return the positions within the specified range
*/
protected Vector getPositionsInRange(Vector v, int offset, int length)
{
Vector res = v;
if (res == null)
res = new Vector();
- else
- res.clear();
int endOffs = offset + length;
Set positionSet = positions.keySet();
for (Iterator i = positionSet.iterator(); i.hasNext();)
{
GapContentPosition p = (GapContentPosition) i.next();
int offs = p.getOffset();
- if (offs >= offset && offs < endOffs)
- res.add(p);
+ if (offs >= offset && offs <= endOffs)
+ res.add(new UndoPosRef(p.mark));
}
return res;
}
/**
* Crunches all positions in the specified range to either the start or
* end of that interval. The interval boundaries are meant to be inclusive
* [start, end].
*
* @param start the start offset of the range
* @param end the end offset of the range
@@ -849,32 +908,44 @@
if (gapStart != 0)
return;
for (int i = 0; i < marks.size(); i++)
{
Mark m = (Mark) marks.get(i);
if (m.mark <= gapEnd)
m.mark = 0;
}
}
/**
- * @specnote This method is not very well specified and the positions vector
- * is implementation specific. The undo positions are managed
- * differently in this implementation, this method is only here
- * for binary compatibility.
+ * Resets the positions in the specified range to their original offset
+ * after a undo operation is performed. For example, after removing some
+ * content, the positions in the removed range will all be set to one
+ * offset. This method restores the positions to their original offsets
+ * after an undo.
+ *
+ * @param positions the positions to update
+ * @param offset
+ * @param length
*/
protected void updateUndoPositions(Vector positions, int offset, int length)
{
- // We do nothing here.
+ for (Iterator i = positions.iterator(); i.hasNext();)
+ {
+ UndoPosRef undoPosRef = (UndoPosRef) i.next();
+ undoPosRef.reset();
+ }
+
+ // Resort marks.
+ Collections.sort(marks);
}
/**
* Outputs debugging info to System.err. It prints out the buffer array,
* the gapStart is marked by a < sign, the gapEnd is marked by a >
* sign and each position is marked by a # sign.
*/
private void dump()
{
System.err.println("GapContent debug information");
System.err.println("buffer length: " + buffer.length);
System.err.println("gap start: " + gapStart);