Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6215849

javax.swing.undo.UndoManager.setLimit() should state that -1 means "no limit"

XMLWordPrintable

    • b92
    • generic, x86
    • generic, windows_xp

      A DESCRIPTION OF THE PROBLEM :
      The Javadoc should specify that setLimit(-1) means no limit should be imposed.


      URL OF FAULTY DOCUMENTATION :
      http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/undo/UndoManager.html#setLimit(int)
      ###@###.### 2005-1-10 22:06:44 GMT
      Suggested fix provided by java.net member leouser:

      A DESCRIPTION OF THE FIX :
      BUG ID: 6215849 javax.swing.undo.UndoManager.setLimit() should state that -1 means "no limit"
      JDK: jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
      FILE AFFECTED: javax.swing.undo.UndoManager

      DISCUSION(embeded in javadoc):
      /**
       * BUG-ID: 6215849 javax.swing.undo.UndoManager.setLimit should state that -1 means "no limit"
       * This is a bad description of the bug, the problem is in essence: there does
       * not appear to be a way to take off the bounds of the UndoManager. Using -1
       * as an indicator is bad, -1 means nothing on its own. Therefore I have chosen
       * to supplement the UndoManager with 2 new methods: setIgnoreLimit and getIgnoreLimit
       * When set to true, the UndoManager will not trim. You can call trimToLimit but
       * it will not affect the quantity of UndoableEdits that have accumalated. Also
       * to ensure clients do not confuse values less than 0 with some kind of special
       * flag I have ensured that setLimit throws an IllegalArgumentException if it is
       * passed a value < 0.
       *
       * ANTI-RATIONALE:
       * 1. You can acheive the same effect by subclassing the UndoManager and add these * methods as well as instrumenting the trimToLimit method to ignore calls to it.
       * 2. UndoManager is not final, subclasses may have added mechanisms to deal with
       * unbounded adding or methods that have names that clash with it. Or the new
       * methods may not work in an already existing subclass given that it may in turn
       * override the trimToLimit method.
       *
       * TESTING STRATEGY: Exercise each new method and described functionality.
       *
       * A NOTE ON WARNINGS:
       * I have removed the cause of I believe 8 warnings. The Vector inside of the
       * UndoManager was not properly generified. Its superclass appears to have
       * been generified but it was not being used as so in the UndoManager.
       *
       * OTHER IDEAS and API Analysis:
       * The UndoManager in my experience has hooks which are good to dig into it. But
       * in many cases when Ive used it Ive had to subclass to get at its guts. For
       * example Ive needed to know the amount of undo's in the stack at one time.
       * There is absolutely no method that will return this value to us. Another
       * time I needed to inspect the guts of the UndoableEdits so I could present
       * a good undo dialog to the user. Again I had to subclass. So this indicates
       * to me:
       * 1. The API for the UndoManager is not sufficient for any use cases that go
       * beyond just store and undo/redo.
       * It may be better to create a new UndoManager class that offers variations on
       * the UndoManager theme... maybe an UndoManager that takes only a certain type
       * of UndoableEdit. At this juncture I consider all these ideas out of scope
       * for this RFE, but are illustrative of holes in the API. If there truly
       * are holes then it may make it impossible in the general case to compose a
       * solution with the UndoManager as a component. Prefering Composition over
       * inheritence cannot be realised.
       *
       * JDK VERSION:
       * jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
       *
       * FILE AFFECTED: javax.swing.undo.UndoManager
       * test ran succesfully on a SUSE 7.3 Linux distribution
       *
       * Brian Harry
       * ###@###.###
       * Thu Jan 11, 2006
       *
       */

      UNIFIED DIFF:
      --- /home/nstuff/java6/jdk1.6.0/javax/swing/undo/UndoManager.java Thu Dec 15 02:17:58 2005
      +++ /home/javarefs/javax/swing/undo/UndoManager.java Wed Jan 11 14:19:43 2006
      @@ -116,8 +116,10 @@
        * @version 1.38, 11/17/05
        */
       public class UndoManager extends CompoundEdit implements UndoableEditListener {
      + static final long serialVersionUID = -2077529998244066750L;
           int indexOfNextAdd;
           int limit;
      + boolean ignoreLimit;
       
           /**
            * Creates a new <code>UndoManager</code>.
      @@ -127,6 +129,7 @@
               indexOfNextAdd = 0;
               limit = 100;
               edits.ensureCapacity(limit);
      + ignoreLimit = false;
           }
       
           /**
      @@ -147,12 +150,12 @@
            * @see AbstractUndoableEdit#die
            */
           public synchronized void discardAllEdits() {
      - Enumeration cursor = edits.elements();
      + Enumeration<UndoableEdit> cursor = edits.elements();
               while (cursor.hasMoreElements()) {
      - UndoableEdit e = (UndoableEdit)cursor.nextElement();
      + UndoableEdit e = cursor.nextElement();
                   e.die();
               }
      - edits = new Vector();
      + edits = new Vector<UndoableEdit>();
               indexOfNextAdd = 0;
               // PENDING(rjrjr) when vector grows a removeRange() method
               // (expected in JDK 1.2), trimEdits() will be nice and
      @@ -164,6 +167,7 @@
            * centered on the index of the next edit.
            */
           protected void trimForLimit() {
      + if(ignoreLimit) return;
               if (limit >= 0) {
                   int size = edits.size();
       // System.out.print("limit: " + limit +
      @@ -221,7 +225,7 @@
       // System.out.println("Trimming " + from + " " + to + " with index " +
       // indexOfNextAdd);
                   for (int i = to; from <= i; i--) {
      - UndoableEdit e = (UndoableEdit)edits.elementAt(i);
      + UndoableEdit e = edits.elementAt(i);
       // System.out.println("JUM: Discarding " +
       // e.getUndoPresentationName());
                       e.die();
      @@ -249,15 +253,53 @@
            * order they were added. The default is 100.
            *
            * @param l the new limit
      + * @throws IllegalArgumentException if l is < 0.
            * @see #addEdit
            * @see #getLimit
            */
           public synchronized void setLimit(int l) {
               if (!inProgress) throw new RuntimeException("Attempt to call UndoManager.setLimit() after UndoManager.end() has been called");
      + else if(l < 0)
      + throw new IllegalArgumentException("l must be >= 0 was " + l);
               limit = l;
               trimForLimit();
           }
      -
      +
      + /**
      + * Sets whether or not this <code>UndoManager</code> instance
      + * will ignore the limit property. If set to true, this
      + * <code>UndoManager</code> will not place any bounds upon how
      + * many <code>UndoableEdits</code> it will accumulate. If set to
      + * false the <code>UndoManager</code> instance will ensure that the
      + * limit is maintained. Setting this value to false when the
      + * limit has been exceeded will result in the size of the
      + * <code>UndoableEdits</code> held to be reduced to the limit.
      + * Default value is false.
      + *
      + * @param ignore whether to ignore the limit or not.
      + * @see #getIgnoreLimit
      + */
      + public synchronized void setIgnoreLimit(boolean ignore){
      + if(!inProgress) throw new RuntimeException("Attempt to call UndoManager.setIgnoreLimit(boolean ignore) after UndoManager.end() has been called");
      + ignoreLimit = ignore;
      + trimForLimit();
      + }
      +
      + /**
      + * Returns whether or not the limit is being ignored. If
      + * the limit is ignored then the <code>UndoManager</code> instance
      + * will place no bounds upon the amount of <code>UndoableEdits</code>
      + * that can accumalate. If the limit is not ignored, this will
      + * be the maximum amount of <code>UndoableEdits</code> this
      + * <code>UndoManager</code> can accumalate.
      + * Default value is false.
      + *
      + * @return boolean whether the limit is ignored or not.
      + * @see #setIgnoreLimit
      + */
      + public synchronized boolean getIgnoreLimit(){
      + return ignoreLimit;
      + }
       
           /**
            * Returns the the next significant edit to be undone if <code>undo</code>
      @@ -269,7 +311,7 @@
           protected UndoableEdit editToBeUndone() {
               int i = indexOfNextAdd;
               while (i > 0) {
      - UndoableEdit edit = (UndoableEdit)edits.elementAt(--i);
      + UndoableEdit edit = edits.elementAt(--i);
                   if (edit.isSignificant()) {
                       return edit;
                   }
      @@ -290,7 +332,7 @@
               int i = indexOfNextAdd;
       
               while (i < count) {
      - UndoableEdit edit = (UndoableEdit)edits.elementAt(i++);
      + UndoableEdit edit = edits.elementAt(i++);
                   if (edit.isSignificant()) {
                       return edit;
                   }
      @@ -309,7 +351,7 @@
           protected void undoTo(UndoableEdit edit) throws CannotUndoException {
               boolean done = false;
               while (!done) {
      - UndoableEdit next = (UndoableEdit)edits.elementAt(--indexOfNextAdd);
      + UndoableEdit next = edits.elementAt(--indexOfNextAdd);
                   next.undo();
                   done = next == edit;
               }
      @@ -325,7 +367,7 @@
           protected void redoTo(UndoableEdit edit) throws CannotRedoException {
               boolean done = false;
               while (!done) {
      - UndoableEdit next = (UndoableEdit)edits.elementAt(indexOfNextAdd++);
      + UndoableEdit next = edits.elementAt(indexOfNextAdd++);
                   next.redo();
                   done = next == edit;
               }


      JUnit TESTCASE :
      import junit.framework.TestCase;
      import junit.textui.TestRunner;
      import static java.lang.System.out;
      import javax.swing.undo.*;

      /**
       * BUG-ID: 6215849 javax.swing.undo.UndoManager.setLimit should state that -1 means "no limit"
       * This is a bad description of the bug, the problem is in essence: there does
       * not appear to be a way to take off the bounds of the UndoManager. Using -1
       * as an indicator is bad, -1 means nothing on its own. Therefore I have chosen
       * to supplement the UndoManager with 2 new methods: setIgnoreLimit and getIgnoreLimit
       * When set to true, the UndoManager will not trim. You can call trimToLimit but
       * it will not affect the quantity of UndoableEdits that have accumalated. Also
       * to ensure clients do not confuse values less than 0 with some kind of special
       * flag I have ensured that setLimit throws an IllegalArgumentException if it is
       * passed a value < 0.
       *
       * ANTI-RATIONALE:
       * 1. You can acheive the same effect by subclassing the UndoManager and add these * methods as well as instrumenting the trimToLimit method to ignore calls to it.
       * 2. UndoManager is not final, subclasses may have added mechanisms to deal with
       * unbounded adding or methods that have names that clash with it. Or the new
       * methods may not work in an already existing subclass given that it may in turn
       * override the trimToLimit method.
       *
       * TESTING STRATEGY: Exercise each new method and described functionality.
       *
       * A NOTE ON WARNINGS:
       * I have removed the cause of I believe 8 warnings. The Vector inside of the
       * UndoManager was not properly generified. Its superclass appears to have
       * been generified but it was not being used as so in the UndoManager.
       *
       * OTHER IDEAS and API Analysis:
       * The UndoManager in my experience has hooks which are good to dig into it. But
       * in many cases when Ive used it Ive had to subclass to get at its guts. For
       * example Ive needed to know the amount of undo's in the stack at one time.
       * There is absolutely no method that will return this value to us. Another
       * time I needed to inspect the guts of the UndoableEdits so I could present
       * a good undo dialog to the user. Again I had to subclass. So this indicates
       * to me:
       * 1. The API for the UndoManager is not sufficient for any use cases that go
       * beyond just store and undo/redo.
       * It may be better to create a new UndoManager class that offers variations on
       * the UndoManager theme... maybe an UndoManager that takes only a certain type
       * of UndoableEdit. At this juncture I consider all these ideas out of scope
       * for this RFE, but are illustrative of holes in the API. If there truly
       * are holes then it may make it impossible in the general case to compose a
       * solution with the UndoManager as a component. Prefering Composition over
       * inheritence cannot be realised.
       *
       * JDK VERSION:
       * jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
       *
       * FILE AFFECTED: javax.swing.undo.UndoManager
       * test ran succesfully on a SUSE 7.3 Linux distribution
       *
       * Brian Harry
       * ###@###.###
       * Thu Jan 11, 2006
       *
       */
      public class TestUM extends TestCase{


          public TestUM(String method){
      super(method);
          }

          public static class UE implements UndoableEdit{

      boolean cr;
      boolean cu;
      public UE(){
      cu = true;
      cr = false;
      }

      public boolean addEdit(UndoableEdit ue){
      return false;
      }
      public boolean canRedo(){
      return cr;
      }
      public boolean canUndo(){
      return cu;
      }
      public void die(){
      cu = cr = false;
      }
      public String getPresentationName(){
      return "I do nothing";
      }
      public String getRedoPresentationName(){
      return "I do nothing";
      }
      public String getUndoPresentationName(){
      return "I do nothing";
      }
      public boolean isSignificant(){ return true; }
      public void redo(){
      cr = false;
      cu = true;
      }
      public void undo(){
      cr = true;
      cu = false;
      }
      public boolean replaceEdit(UndoableEdit ue){
      return false;
      }


          }

          public void testUMIgnore(){

      out.println("");
      out.println("Testing to see if limit is ignored...");
      UndoManager um = new UndoManager();
      um.setLimit(100);
      um.setIgnoreLimit(true);
      out.println( "Limit is " + um.getLimit() );
      out.println( "Adding 1000 UndoableEdit instances" );
      for(int i = 0; i < 1000;i++)
      um.addEdit(new UE());

      out.println("Let us see if the limit is ignored...");
      int x = 0;
      while(um.canUndo()){
      um.undo();
      x++;
      }
      assertEquals(1000,x);
      out.println("Limit was ignored! success!");

          }

          public void testUMNotIgnore(){

      out.println("");
      out.println("Testing to see if limit is not ignored...");
      UndoManager um = new UndoManager();
      um.setLimit(100);
      um.setIgnoreLimit(false);
      out.println( "Limit is " + um.getLimit() );
      out.println( "Adding 1000 UndoableEdit instances" );
      for(int i = 0; i < 1000;i++)
      um.addEdit(new UE());

      out.println("Let us see if the limit is not ignored...");
      int x = 0;
      while(um.canUndo()){
      um.undo();
      x++;
      }
      assertEquals(100,x);
      out.println("Limit was not ignored! success!");

          }

          public void testUMTrim(){

      out.println("");
      out.println("Testing to see if setIgnoreLimit will trim if set to false after adding 1000 UEs ");
      UndoManager um = new UndoManager();
      um.setLimit(100);
      um.setIgnoreLimit(true);
      out.println( "Limit is " + um.getLimit() );
      out.println( "Adding 1000 UndoableEdit instances" );
      for(int i = 0; i < 1000;i++)
      um.addEdit(new UE());

      um.setIgnoreLimit(false);
      out.println("Let us see if the setIgnoreLimit trims...");
      int x = 0;
      while(um.canUndo()){
      um.undo();
      x++;
      }
      assertEquals(100,x);
      out.println("trim was executed!");

          }

        
          public void testUMLTZ(){

      out.println("");
      out.println("Testing to see if setLimit with values less than 0 will throw an IllegalArgumentException");
      try{
      UndoManager um = new UndoManager();
      um.setLimit(-1);
      }
      catch(IllegalArgumentException iae){
      out.println( "IllegalArgumentException is tossed as expected");
      }

          }


          public static void main(String ... args){

      TestCase tc = new TestUM("testUMIgnore");
      TestRunner.run(tc);
      TestCase tc2 = new TestUM("testUMNotIgnore");
      TestRunner.run(tc2);
      TestCase tc3 = new TestUM("testUMTrim");
      TestRunner.run(tc3);
      TestCase tc4 = new TestUM("testUMLTZ");
      TestRunner.run(tc4);
          }


      }


      FIX FOR BUG NUMBER:
      6215849

            svioletsunw Scott Violet (Inactive)
            rmandalasunw Ranjith Mandala (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: