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 &lt; sign, the gapEnd is marked by a &gt;
    * 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);

Reply via email to