StateEdit.java (getPresentationName): Docfix.
authorSascha Brawer <brawer@dandelis.ch>
Wed, 26 Nov 2003 22:23:40 +0000 (23:23 +0100)
committerMichael Koch <mkoch@gcc.gnu.org>
Wed, 26 Nov 2003 22:23:40 +0000 (22:23 +0000)
2003-11-26  Sascha Brawer  <brawer@dandelis.ch>

* javax/swing/undo/StateEdit.java (getPresentationName): Docfix.
* javax/swing/undo/AbstractUndoableEdit.java (canUndo, canRedo,
isSignificant): Likewise.

2003-11-26  Sascha Brawer  <brawer@dandelis.ch>

* javax/swing/undo/CompoundEdit.java: Re-format, document.
(inProgress): Set initial value to true.
(undo, redo, die, canUndo, canRedo): Also call inherited
implementation; simplify code structure.
(getPresentationName, getUndoPresentationName,
getRedoPresentationName): Make behavior dependent on lastEdit.
(addEdit, isSignificant): Completely re-written.

2003-11-26  Sascha Brawer  <brawer@dandelis.ch>

* javax/swing/undo/StateEdit.java: Re-format, document.
(undo, redo): Also call inherited implementation.

2003-11-26  Sascha Brawer  <brawer@dandelis.ch>

* javax/swing/undo/StateEditable.java: Re-format, document.

2003-11-26  Sascha Brawer  <brawer@dandelis.ch>

* javax/swing/undo/AbstractUndoableEdit.java: Re-format, document.
(AbstractUndoableEdit): Initialize hasBeenDone to true.
(canUndo, canRedo): Simplify.
(getUndoPresentationName, getRedoPresentationName): Support
localized message; call getPresentationName() only once.

From-SVN: r73967

libjava/ChangeLog
libjava/javax/swing/undo/AbstractUndoableEdit.java
libjava/javax/swing/undo/CannotRedoException.java
libjava/javax/swing/undo/CannotUndoException.java
libjava/javax/swing/undo/CompoundEdit.java
libjava/javax/swing/undo/StateEdit.java
libjava/javax/swing/undo/StateEditable.java

index bf2ffaeed6917fba0936c6cb7d9079c8b09f4b3f..d14bfdea90de4b749f3134a6416e5170f6566020 100644 (file)
@@ -1,3 +1,36 @@
+2003-11-26  Sascha Brawer  <brawer@dandelis.ch>
+
+       * javax/swing/undo/StateEdit.java (getPresentationName): Docfix.
+       * javax/swing/undo/AbstractUndoableEdit.java (canUndo, canRedo,
+       isSignificant): Likewise.
+
+2003-11-26  Sascha Brawer  <brawer@dandelis.ch>
+
+       * javax/swing/undo/CompoundEdit.java: Re-format, document.
+       (inProgress): Set initial value to true.
+       (undo, redo, die, canUndo, canRedo): Also call inherited
+       implementation; simplify code structure.
+       (getPresentationName, getUndoPresentationName,
+       getRedoPresentationName): Make behavior dependent on lastEdit.
+       (addEdit, isSignificant): Completely re-written.
+
+2003-11-26  Sascha Brawer  <brawer@dandelis.ch>
+
+       * javax/swing/undo/StateEdit.java: Re-format, document.
+       (undo, redo): Also call inherited implementation.
+
+2003-11-26  Sascha Brawer  <brawer@dandelis.ch>
+
+       * javax/swing/undo/StateEditable.java: Re-format, document.
+
+2003-11-26  Sascha Brawer  <brawer@dandelis.ch>
+
+       * javax/swing/undo/AbstractUndoableEdit.java: Re-format, document.
+       (AbstractUndoableEdit): Initialize hasBeenDone to true.
+       (canUndo, canRedo): Simplify.
+       (getUndoPresentationName, getRedoPresentationName): Support
+       localized message; call getPresentationName() only once.
+
 2003-11-26  David Belanger  <dbelan2@cs.mcgill.ca>
 
        * java/util/zip/ZipFile (Zipfile(File)): Set file path as name.
index d845e4341bbe705a5410232623a75fbebf206c40..e694c0a447f884ea3b26ce46fc497e7a0cb92c4b 100644 (file)
@@ -1,4 +1,4 @@
-/* AbstractTableModel.java --
+/* AbstractUndoableEdit.java
    Copyright (C) 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
@@ -39,180 +39,285 @@ exception statement from your version. */
 package javax.swing.undo;
 
 import java.io.Serializable;
+import javax.swing.UIManager;
+
 
 /**
- * AbstractUndoableEdit
- * @author Andrew Selkirk
+ * A default implementation of <code>UndoableEdit</code> that can be
+ * used as a base for implementing editing operations.
+ *
+ * @author Andrew Selkirk (aselkirk@sympatico.ca)
+ * @author Sascha Brawer (brawer@dandelis.ch)
  */
-public class AbstractUndoableEdit implements UndoableEdit, Serializable
+public class AbstractUndoableEdit
+  implements UndoableEdit, Serializable
 {
+  /**
+   * The serialization ID.  Verified using the <code>serialver</code>
+   * tool of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5, and Sun JDK
+   * 1.4.1_01 on GNU/Linux.
+   */
   static final long serialVersionUID = 580150227676302096L;
 
-  //-------------------------------------------------------------
-  // Constants --------------------------------------------------
-  //-------------------------------------------------------------
 
   /**
-   * String returned by getRedoPresentationName()
+   * The constant string &#x201c;Undo&#x201d;, which was returned by
+   * {@link #getUndoPresentationName()} on early versions of the
+   * platform. However, this field has become obsolete with version
+   * 1.3.1.  That method now retrieves a localized string from the
+   * {@link javax.swing.UIManager}, using the key
+   * <code>&#x201c;AbstractUndoableEdit.undoText&#x201d;</code>.
    */
-  protected static final String RedoName = "Redo";
+  protected static final String UndoName = "Undo";
+
 
   /**
-   * String returned by getUndoPresentationName()
+   * The constant string &#x201c;Redo&#x201d;, which was returned by
+   * {@link #getRedoPresentationName()} on early versions of the
+   * platform. However, this field has become obsolete with version
+   * 1.3.1.  That method now retrieves a localized string from the
+   * {@link javax.swing.UIManager}, using the key
+   * <code>&#x201c;AbstractUndoableEdit.redoText&#x201d;</code>.
    */
-  protected static final String UndoName = "Undo";
-
+  protected static final String RedoName = "Redo";
 
-  //-------------------------------------------------------------
-  // Variables --------------------------------------------------
-  //-------------------------------------------------------------
 
   /**
-   * TODO
+   * Indicates whether this editing action has been executed.  A value
+   * of <code>true</code> means that the action was performed, or that
+   * a redo operation was successful. A value of <code>false</code>
+   * means that the action has not yet performed, or that an undo
+   * operation was successful.
    */
-  private boolean hasBeenDone = false;
+  private boolean hasBeenDone;
+
 
   /**
-   * The edit is alive
+   * Indicates whether this editing action is still alive. The value
+   * is set to <code>true</code> by the constructor, and to
+   * <code>false</code> by the {@link #die()} method.
    */
-  private boolean alive = true;
+  private boolean alive;
 
 
-  //-------------------------------------------------------------
-  // Initialization ---------------------------------------------
-  //-------------------------------------------------------------
-
   /**
-   * Create new AbstractUndoableEdit
+   * Constructs a new <code>AbstractUndoableEdit</code>. The initial
+   * state is that the editing action is alive, and
+   * <code>hasBeenDone</code> is <code>true</code>.
    */
   public AbstractUndoableEdit()
   {
-  } // AbstractUndoableEdit()
-
+    // The API specification is not clear, but Mauve test code has
+    // determined that hasBeenDone is initially set to true.
+    alive = hasBeenDone = true;
+  }
 
-  //-------------------------------------------------------------
-  // Interface: UndoableEdit ------------------------------------
-  //-------------------------------------------------------------
 
   /**
-   * addEdit
-   * @param anEdit TODO
-   * @returns TODO
+   * Undoes this editing action.
+   *
+   * @throws CannotUndoException if {@link #canUndo()} returns
+   * <code>false</code>, for example because this action has already
+   * been undone.
+   *
+   * @see #canUndo()
+   * @see #redo()
    */
-  public boolean addEdit(UndoableEdit anEdit)
+  public void undo()
+    throws CannotUndoException
   {
-    return false;
-  } // addEdit()
-
+    if (!canUndo())
+      throw new CannotUndoException();
+    hasBeenDone = false;
+  }
+  
+  
   /**
-   * canRedo()
-   * @returns true if redoable, false otherwise
+   * Determines whether it would be possible to undo this editing
+   * action.
+   *
+   * @return <code>true</code> to indicate that this action can be
+   * undone, <code>false</code> otherwise.
+   *
+   * @see #undo()
+   * @see #canRedo()
    */
-  public boolean canRedo()
+  public boolean canUndo()
   {
-    if (alive == true && hasBeenDone == false)
-      return true;
-    return false;
-  } // canRedo()
-
+    return alive && hasBeenDone;
+  }
+  
+  
   /**
-   * canUndo()
-   * @returns true if undoable, false otherwise
+   * Redoes this editing action.
+   *
+   * @throws CannotRedoException if {@link #canRedo()} returns
+   * <code>false</code>, for example because this action has not
+   * yet been undone.
+   *
+   * @see #canRedo()
+   * @see #undo()
    */
-  public boolean canUndo()
+  public void redo()
+    throws CannotRedoException
   {
-    if (alive == true && hasBeenDone == true)
-      return true;
-    return false;
-  } // canUndo()
-
+    if (!canRedo())
+      throw new CannotRedoException();
+    hasBeenDone = true;
+  }
+  
+  
   /**
-   * die
+   * Determines whether it would be possible to redo this editing
+   * action.
+   *
+   * @return <code>true</code> to indicate that this action can be
+   * redone, <code>false</code> otherwise.
+   *
+   * @see #redo()
+   * @see #canUndo()
    */
-  public void die()
+  public boolean canRedo()
   {
-    alive = false;
-  } // die()
+    return alive && !hasBeenDone;
+  }
+
 
   /**
-   * getPresentation
-   * @returns TODO
+   * Informs this edit action that it will no longer be used. Some
+   * actions might use this information to release resources, for
+   * example open files.  Called by {@link UndoManager} before this
+   * action is removed from the edit queue.
    */
-  public String getPresentationName()
+  public void die()
   {
-    return "";
-  } // getPresentationName()
+    alive = false;
+  }
+
 
   /**
-   * getRedoPresentationName
-   * @returns TODO
+   * Incorporates another editing action into this one, thus forming a
+   * combined action.
+   *
+   * <p>The default implementation always returns <code>false</code>,
+   * indicating that the editing action could not be incorporated.
+   *
+   * @param edit the editing action to be incorporated.
    */
-  public String getRedoPresentationName()
+  public boolean addEdit(UndoableEdit edit)
   {
-    if (getPresentationName().equals(""))
-      return RedoName;
-    return RedoName + " " + getPresentationName();
-  } // getRedoPresentationName()
-
+    return false;
+  }
+  
+  
   /**
-   * getUndoPresentationName
-   * @returns TODO
+   * Incorporates another editing action into this one, thus forming a
+   * combined action that replaces the argument action.
+   *
+   * <p>The default implementation always returns <code>false</code>,
+   * indicating that the argument action should not be replaced.
+   *
+   * @param edit the editing action to be replaced.
    */
-  public String getUndoPresentationName()
+  public boolean replaceEdit(UndoableEdit edit)
   {
-    if (getPresentationName().equals(""))
-      return UndoName;
-    return UndoName + " " + getPresentationName();
-  } // getUndoPresentationName()
-
+    return false;
+  }
+  
+  
   /**
-   * isSignificant
-   * @returns true
+   * Determines whether this editing action is significant enough for
+   * being seperately undoable by the user. A typical significant
+   * action would be the resizing of an object. However, changing the
+   * selection in a text document would usually not be considered
+   * significant.
+   *
+   * <p>The default implementation returns <code>true</code>.
+   *
+   * @return <code>true</code> to indicate that the action is
+   * significant enough for being separately undoable, or
+   * <code>false</code> otherwise.
    */
   public boolean isSignificant()
   {
     return true;
-  } // isSignificant()
-
+  }
+  
+  
   /**
-   * redo
-   * @throws CannotRedoException TODO
+   * Returns a human-readable, localized name that describes this
+   * editing action and can be displayed to the user.
+   *
+   * <p>The default implementation returns an empty string.
    */
-  public void redo() throws CannotRedoException
+  public String getPresentationName()
   {
-    if (! canRedo())
-      throw new CannotRedoException();
-    hasBeenDone = true;
-  } // redo()
+    return "";
+  }
+
 
   /**
-   * replaceEdit
-   * @param anEdit TODO
-   * @returns TODO
+   * Calculates a localized name for presenting the undo action to the
+   * user.
+   *
+   * <p>The default implementation returns the concatenation of the
+   * string &#x201c;Undo&#x201d; and the action name, which is
+   * determined by calling {@link #getPresentationName()}.
+   *
+   * <p>The string &#x201c;Undo&#x201d; is retrieved from the {@link
+   * javax.swing.UIManager}, using the key
+   * <code>&#x201c;AbstractUndoableEdit.undoText&#x201d;</code>.  This
+   * allows the text to be localized.
    */
-  public boolean replaceEdit(UndoableEdit anEdit)
+  public String getUndoPresentationName()
   {
-    return false;
-  } // replaceEdit()
+    String msg, pres;
+
+    msg = UIManager.getString("AbstractUndoableEdit.undoText");
+    if (msg == null)
+      msg = UndoName;
+
+    pres = getPresentationName();
+    if ((pres == null) || (pres.length() == 0))
+      return msg;
+    else
+      return msg + ' ' + pres;
+  }
+
 
   /**
-   * String representation
-   * @returns String representation
+   * Calculates a localized name for presenting the redo action to the
+   * user.
+   *
+   * <p>The default implementation returns the concatenation of the
+   * string &#x201c;Redo&#x201d; and the action name, which is
+   * determined by calling {@link #getPresentationName()}.
+   *
+   * <p>The string &#x201c;Redo&#x201d; is retrieved from the {@link
+   * javax.swing.UIManager}, using the key
+   * <code>&#x201c;AbstractUndoableEdit.redoText&#x201d;</code>.  This
+   * allows the text to be localized.
    */
-  public String toString()
+  public String getRedoPresentationName()
   {
-    return (super.toString() + " hasBeenDone: " + hasBeenDone
-           + " alive: " + alive);
+    String msg, pres;
+
+    msg = UIManager.getString("AbstractUndoableEdit.redoText");
+    if (msg == null)
+      msg = RedoName;
+
+    pres = getPresentationName();
+    if ((pres == null) || (pres.length() == 0))
+      return msg;
+    else
+      return msg + ' ' + pres;
   }
 
-  /**
-   * undo
-   * @throws CannotUndoException TODO
-   */
-  public void undo() throws CannotUndoException
+
+  public String toString()
   {
-    if (! canUndo())
-      throw new CannotUndoException();
-    hasBeenDone = false;
-  } // undo()
-} // AbstractUndoableEdit
+    return super.toString()
+      + " hasBeenDone: " + hasBeenDone
+      + " alive: " + alive;
+  }
+}
index 030975d4f1de98198b487d15619a481e34707dd8..f482b75bb979c1ee5bef1142bc95df594d200b73 100644 (file)
@@ -1,5 +1,5 @@
-/* AbstractTableModel.java --
-   Copyright (C) 2002 Free Software Foundation, Inc.
+/* CannotRedoException.java
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -38,17 +38,19 @@ exception statement from your version. */
 package javax.swing.undo;
 
 /**
- * CannotRedoException
- * @author Andrew Selkirk
+ * An exception which indicates that an editing action cannot be
+ * redone.
+ *
+ * @author Andrew Selkirk (aselkirk@sympatico.ca)
+ * @author Sascha Brawer (brawer@dandelis.ch)
  */
-public class CannotRedoException extends RuntimeException {
-
-       /**
-        * Create exception
-        */
-       public CannotRedoException() {
-               super();
-       } // CannotRedoException()
-
-
-} // CannotRedoException
+public class CannotRedoException
+  extends RuntimeException
+{
+  /**
+   * Constructs a new instance of a <code>CannotRedoException</code>.
+   */
+  public CannotRedoException()
+  {
+  }
+}
index c039d1bbebd1653a8ada72fb6e57a8be224412ae..0193921ed192cb497e16c4125f7bce233870b26f 100644 (file)
@@ -1,5 +1,5 @@
-/* AbstractTableModel.java --
-   Copyright (C) 2002 Free Software Foundation, Inc.
+/* CannotUndoException.java
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -37,18 +37,21 @@ exception statement from your version. */
 
 package javax.swing.undo;
 
+
 /**
- * CannotUndoException
- * @author Andrew Selkirk
+ * An exception which indicates that an editing action cannot be
+ * undone.
+ *
+ * @author Andrew Selkirk (aselkirk@sympatico.ca)
+ * @author Sascha Brawer (brawer@dandelis.ch)
  */
-public class CannotUndoException extends RuntimeException {
-
-       /**
-        * Create exception
-        */
-       public CannotUndoException() {
-               super();
-       } // CannotUndoException()
-
-
-} // CannotUndoException
+public class CannotUndoException
+  extends RuntimeException
+{
+  /**
+   * Constructs a new instance of a <code>CannotUndoException</code>.
+   */
+  public CannotUndoException()
+  {
+  }
+}
index be612dad77b7a87c1bc8b18492399a9a9c600c75..12ff2bd36ec9f1044d35a395262c122fbe852713 100644 (file)
@@ -1,5 +1,5 @@
-/* AbstractTableModel.java --
-   Copyright (C) 2002 Free Software Foundation, Inc.
+/* CompoundEdit.java -- Combines multiple UndoableEdits.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -41,242 +41,352 @@ package javax.swing.undo;
 import java.util.Vector;
 
 /**
- * CompoundEdit
- * @author Andrew Selkirk
+ * An editing action that consists of multiple
+ * <code>UndoableEdits</code>.
+ *
+ * <p>The use of a <code>CompoundEdit</code> is divided in two separate
+ * phases.
+ *
+ * <ol><li>In the first phase, the <code>CompoundEdit</code> is
+ * initialized.  After a new instance of <code>CompoundEdit</code> has
+ * been created, {@link #addEdit(UndoableEdit)} is called for each
+ * element of the compound.  To terminate the initialization phase,
+ * call {@link #end()}.</li>
+ *
+ * <li>In the second phase, the the <code>CompoundEdit</code> can be
+ * used, typically by invoking {@link #undo()} and {@link
+ * #redo()}.</li></ol>
+ *
+ * @author Andrew Selkirk (aselkirk@sympatico.ca)
+ * @author Sascha Brawer (brawer@dandelis.ch)
  */
-public class CompoundEdit extends AbstractUndoableEdit {
-
-       //-------------------------------------------------------------
-       // Variables --------------------------------------------------
-       //-------------------------------------------------------------
-
-       /**
-        * The collection of UndoableEdits undone/redone en
-        * masse by this CompoundEdit
-        */
-       protected       Vector  edits           = new Vector();
-
-       /**
-        * TODO
-        */
-       private         boolean inProgress      = false;
-
-
-       //-------------------------------------------------------------
-       // Initialization ---------------------------------------------
-       //-------------------------------------------------------------
-
-       /**
-        * Create new Compound Edit
-        */
-       public CompoundEdit() {
-       } // CompoundEdit()
-
-
-       //-------------------------------------------------------------
-       // Interface: UndoableEdit ------------------------------------
-       //-------------------------------------------------------------
-
-       /**
-        * addEdit
-        * @param anEdit TODO
-        * @returns TODO
-        */
-       public boolean addEdit(UndoableEdit anEdit) {
-
-               // Variables
-               UndoableEdit    lastEdit;
-
-               if (inProgress == true) {
-
-                       // Get Last Edit
-                       lastEdit = lastEdit();
-
-                       // Check for null
-                       if (lastEdit != null) {
-
-                               if (lastEdit.addEdit(anEdit) == false) {
-                                       if (lastEdit.replaceEdit(anEdit) == false) {
-                                               edits.add(anEdit);
-                                       }
-                               }
-
-                       } // if: lastEdit
-
-                       return true;
-
-               } else {
-                       return false;
-               }
-       } // addEdit()
-
-       /**
-        * canRedo
-        * @returns TODO
-        */
-       public boolean canRedo() {
-               if (isInProgress() == true || super.canRedo() == false) {
-                       return false;
-               }
-               return true;
-       } // canRedo()
-
-       /**
-        * canUndo
-        * @returns TODO
-        */
-       public boolean canUndo() {
-               if (isInProgress() == true || super.canUndo() == false) {
-                       return false;
-               }
-               return true;
-       } // canUndo()
-
-       /**
-        * die
-        */
-       public void die() {
-
-               // Variables
-               int                             index;
-               UndoableEdit    current;
-
-               // Loop through all contained UndoableEdits
-               for (index = edits.size() - 1; index >= 0; index--) {
-                       current = (UndoableEdit) edits.elementAt(index);
-                       current.die();
-               } // for: index
-
-       } // die()
-
-       /**
-        * end
-        */
-       public void end() {
-               inProgress = false;
-       } // end()
-
-       /**
-        * getPresentationName
-        * @returns TODO
-        */
-       public String getPresentationName() {
-               if (edits.size() == 0) {
-                       return super.getPresentationName();
-               } else {
-                       return lastEdit().getPresentationName();
-               }
-       } // getPresentationName()
-
-       /**
-        * getRedoPresentationName
-        * @returns TODO
-        */
-       public String getRedoPresentationName() {
-               if (edits.size() == 0) {
-                       return super.getRedoPresentationName();
-               } else {
-                       return lastEdit().getRedoPresentationName();
-               }
-       } // getRedoPresentationName()
-
-       /**
-        * getUndoPresentationName
-        * @returns TODO
-        */
-       public String getUndoPresentationName() {
-               if (edits.size() == 0) {
-                       return super.getUndoPresentationName();
-               } else {
-                       return lastEdit().getUndoPresentationName();
-               }
-       } // getUndoPresentationName()
-
-       /**
-        * isInProgress
-        * @returns TODO
-        */
-       public boolean isInProgress() {
-               return inProgress;
-       } // isInProgress()
-
-
-       /**
-        * isSignigicant
-        * @returns TODO
-        */
-       public boolean isSignificant() {
-
-               // Variables
-               int                             index;
-               UndoableEdit    current;
-
-               // Check each edit
-               for (index = 0; index < edits.size(); index++) {
-                       current = (UndoableEdit) edits.elementAt(index);
-                       if (current.isSignificant() == true) {
-                               return true;
-                       }
-               } // for: index
-
-               return false;
-
-       } // isSignificant()
-
-       /**
-        * lastEdit
-        * @returns TODO
-        */
-       protected UndoableEdit lastEdit() {
-               if (edits.size() == 0) {
-                       return null;
-               }
-               return (UndoableEdit) edits.elementAt(edits.size() - 1);
-       } // lastEdit()
-
-       /**
-        * redo
-        * @throws CannotRedoException TODO
-        */
-       public void redo() throws CannotRedoException {
-
-               // Variables
-               int                             index;
-               UndoableEdit    current;
-
-               // Loop through all contained UndoableEdits
-               for (index = 0; index < edits.size(); index++) {
-                       current = (UndoableEdit) edits.elementAt(index);
-                       current.redo();
-               } // for: index
-
-       } // redo()
-
-       /**
-        * String representation
-        * @returns String representation
-        */
-       public String toString() {
-               return null; // TODO
-       } // toString()
-
-       /**
-        * undo
-        * @throws CannotUndoException TODO
-        */
-       public void undo() throws CannotUndoException {
-
-               // Variables
-               int                             index;
-               UndoableEdit    current;
-
-               // Loop through all contained UndoableEdits
-               for (index = edits.size() - 1; index >= 0; index--) {
-                       current = (UndoableEdit) edits.elementAt(index);
-                       current.undo();
-               } // for: index
-
-       } // undo()
-
-
-} // CompoundEdit
+public class CompoundEdit
+  extends AbstractUndoableEdit
+{
+  /**
+   * The <code>UndoableEdit</code>s being combined into a compound
+   * editing action.
+   */
+  protected Vector edits;
+
+
+  /**
+   * Indicates whether the creation of this CompoundEdit is still in
+   * progress. Initially, the value of this flag is
+   * <code>true</code>. The {@link #end()} method changes the flag to
+   * <code>false</code>. 
+   */
+  private boolean inProgress;
+
+
+  /**
+   * Constructs a new CompoundEdit.
+   */
+  public CompoundEdit()
+  {
+    edits = new Vector();
+    inProgress = true;
+  }
+  
+
+  /**
+   * Undoes all edits that are part of of this
+   * <code>CompoundEdit</code>. The compound elements will receive the
+   * <code>undo</code> message in the reverse order of addition.
+   *
+   * @throws CannotUndoException if {@link #canUndo()} returns
+   * <code>false</code>. This can happen if {@link #end()} has not
+   * been called on this <code>CompoundEdit</code>, or if this edit
+   * has already been undone.
+   *
+   * @see #canUndo()
+   * @see #redo()
+   */
+  public void undo()
+    throws CannotUndoException
+  {
+    // AbstractUndoableEdit.undo() will throw a CannotUndoException if
+    // canUndo returns false.
+    super.undo();
+
+    for (int i = edits.size() - 1; i >= 0; i--)
+      ((UndoableEdit) edits.elementAt(i)).undo();
+  }
+
+
+  /**
+   * Redoes all edits that are part of of this
+   * <code>CompoundEdit</code>. The compound elements will receive the
+   * <code>undo</code> message in the same order as they were added.
+   *
+   * @throws CannotRedoException if {@link #canRedo()} returns
+   * <code>false</code>. This can happen if {@link #end()} has not
+   * been called on this <code>CompoundEdit</code>, or if this edit
+   * has already been redone.
+   *
+   * @see #canRedo()
+   * @see #undo()
+   */
+  public void redo()
+    throws CannotRedoException
+  {
+    // AbstractUndoableEdit.redo() will throw a CannotRedoException if
+    // canRedo returns false.
+    super.redo();
+
+    for (int i = 0; i < edits.size(); i++)
+      ((UndoableEdit) edits.elementAt(i)).redo();
+  }
+
+  
+  /**
+   * Returns the the <code>UndoableEdit</code> that was last added to
+   * this compound.
+   */
+  protected UndoableEdit lastEdit()
+  {
+    if (edits.size() == 0)
+      return null;
+    else
+      return (UndoableEdit) edits.elementAt(edits.size() - 1);
+  }
+
+
+  /**
+   * Informs this edit action, and all compound edits, that they will
+   * no longer be used. Some actions might use this information to
+   * release resources such as open files.  Called by {@link
+   * UndoManager} before this action is removed from the edit queue.
+   *
+   * <p>The compound elements will receive the
+   * <code>die</code> message in the reverse order of addition.
+   */
+  public void die()
+  {
+    for (int i = edits.size() - 1; i >= 0; i--)
+      ((UndoableEdit) edits.elementAt(i)).die();
+
+    super.die();
+  }
+
+
+  /**
+   * Incorporates another editing action into this one, thus forming a
+   * combined edit.
+   *
+   * <p>If this edit&#x2019;s {@link #end()} method has been called
+   * before, <code>false</code> is returned immediately. Otherwise,
+   * the {@linkplain #lastEdit() last added edit} is given the
+   * opportunity to {@linkplain UndoableEdit#addEdit(UndoableEdit)
+   * incorporate} <code>edit</code>.  If this fails, <code>edit</code>
+   * is given the opportunity to {@linkplain
+   * UndoableEdit#replaceEdit(UndoableEdit) replace} the last added
+   * edit.  If this fails as well, <code>edit</code> gets added as a
+   * new compound to {@link #edits}.
+   * 
+   * @param edit the editing action being added.
+   *
+   * @return <code>true</code> if <code>edit</code> could somehow be
+   * incorporated; <code>false</code> if <code>edit</code> has not
+   * been incorporated because {@link #end()} was called before.
+   */
+  public boolean addEdit(UndoableEdit edit)
+  {
+    UndoableEdit last;
+
+    // If end has been called before, do nothing.
+    if (!inProgress)
+      return false;
+
+    last = lastEdit();
+
+    // If edit is the very first edit, just add it to the list.
+    if (last == null)
+    {
+      edits.add(edit);
+      return true;
+    }
+
+    // Try to incorporate edit into last.
+    if (last.addEdit(edit))
+      return true;
+
+    // Try to replace last by edit.
+    if (edit.replaceEdit(last))
+    {
+      edits.set(edits.size() - 1, edit);
+      return true;
+    }
+
+    // If everything else has failed, add edit to the list of compound
+    // edits.
+    edits.add(edit);
+    return true;
+  }
+
+
+  /**
+   * Informs this <code>CompoundEdit</code> that its construction
+   * phase has been completed. After this method has been called,
+   * {@link #undo()} and {@link #redo()} may be called, {@link
+   * #isInProgress()} will return <code>false</code>, and all attempts
+   * to {@linkplain #addEdit(UndoableEdit) add further edits} will
+   * fail.
+   */
+  public void end()
+  {
+    inProgress = false;
+  }
+
+
+  /**
+   * Determines whether it would be possible to undo this editing
+   * action. The result will be <code>true</code> if {@link #end()}
+   * has been called on this <code>CompoundEdit</code>, {@link #die()}
+   * has not yet been called, and the edit has not been undone
+   * already.
+   *
+   * @return <code>true</code> to indicate that this action can be
+   * undone; <code>false</code> otherwise.
+   *
+   * @see #undo()
+   * @see #canRedo()
+   */
+  public boolean canUndo()
+  {
+    return !inProgress && super.canUndo();
+  }
+
+
+  /**
+   * Determines whether it would be possible to redo this editing
+   * action. The result will be <code>true</code> if {@link #end()}
+   * has been called on this <code>CompoundEdit</code>, {@link #die()}
+   * has not yet been called, and the edit has not been redone
+   * already.
+   *
+   * @return <code>true</code> to indicate that this action can be
+   * redone; <code>false</code> otherwise.
+   *
+   * @see #redo()
+   * @see #canUndo()
+   */
+  public boolean canRedo()
+  {
+    return !inProgress && super.canRedo();
+  }
+
+
+  /**
+   * Determines whether the initial construction phase of this
+   * <code>CompoundEdit</code> is still in progress.  During this
+   * phase, edits {@linkplain #addEdit(UndoableEdit) may be
+   * added}. After initialization has been terminated by calling
+   * {@link #end()}, {@link #undo()} and {@link #redo()} can be used.
+   *
+   * @return <code>true</code> if the initialization phase is still in
+   * progress; <code>false</code> if {@link #end()} has been called.
+   *
+   * @see #end()
+   */
+  public boolean isInProgress()
+  {
+    return inProgress;
+  }
+
+
+  /**
+   * Determines whether this editing action is significant enough for
+   * being seperately undoable by the user. A typical significant
+   * action would be the resizing of an object. However, changing the
+   * selection in a text document would usually not be considered
+   * significant.
+   *
+   * <p>A <code>CompoundEdit</code> is significant if any of its
+   * elements are significant.
+   */
+  public boolean isSignificant()
+  {
+    for (int i = edits.size() - 1; i >= 0; i--)
+      if (((UndoableEdit) edits.elementAt(i)).isSignificant())
+        return true;
+
+    return false;
+  }
+  
+
+  /**
+   * Returns a human-readable, localized name that describes this
+   * editing action and can be displayed to the user.
+   *
+   * <p>The implementation delegates the call to the {@linkplain
+   * #lastEdit() last added edit action}. If no edit has been added
+   * yet, the inherited implementation will be invoked, which always
+   * returns an empty string.
+   */
+  public String getPresentationName()
+  {
+    UndoableEdit last;
+
+    last = lastEdit();
+    if (last == null)
+      return super.getPresentationName();
+    else
+      return last.getPresentationName();
+  }
+
+
+  /**
+   * Calculates a localized message text for presenting the undo
+   * action to the user.
+   *
+   * <p>The implementation delegates the call to the {@linkplain
+   * #lastEdit() last added edit action}. If no edit has been added
+   * yet, the {@linkplain
+   * AbstractUndoableEdit#getUndoPresentationName() inherited
+   * implementation} will be invoked.
+   */
+  public String getUndoPresentationName()
+  {
+    UndoableEdit last;
+
+    last = lastEdit();
+    if (last == null)
+      return super.getUndoPresentationName();
+    else
+      return last.getUndoPresentationName();
+  }
+
+
+  /**
+   * Calculates a localized message text for presenting the redo
+   * action to the user.
+   *
+   * <p>The implementation delegates the call to the {@linkplain
+   * #lastEdit() last added edit action}. If no edit has been added
+   * yet, the {@linkplain
+   * AbstractUndoableEdit#getRedoPresentationName() inherited
+   * implementation} will be invoked.
+   */
+  public String getRedoPresentationName()
+  {
+    UndoableEdit last;
+
+    last = lastEdit();
+    if (last == null)
+      return super.getRedoPresentationName();
+    else
+      return last.getRedoPresentationName();
+  }
+  
+  
+  /**
+   * Calculates a string that may be useful for debugging.
+   */
+  public String toString()
+  {
+    return super.toString()
+      + " inProgress: " + inProgress
+      + " edits: " + edits;
+  }
+}
index 6a32fbdb48d1f96ba02aee679b42a1e0517d1264..00f1e2d830c41b5f96f2455ac79a806ed1842e50 100644 (file)
@@ -1,4 +1,4 @@
-/* StateEdit.java --
+/* StateEdit.java -- UndoableEdit for StateEditable implementations.
    Copyright (C) 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
@@ -42,59 +42,118 @@ import java.util.Hashtable;
 import java.util.Iterator;
 
 /**
- * StateEdit
- * @author     Andrew Selkirk
+ * A helper class, making it easy to support undo and redo.
+ *
+ * <p>The following example shows how to use this class.
+ *
+ * <pre>  Foo foo; // class Foo implements {@link StateEditable}
+ *  StateEdit edit;
+ *
+ *  edit = new StateEdit(foo, "Name Change");
+ *  foo.setName("Jane Doe");
+ *  edit.end();
+ *  undoManager.addEdit(edit);</pre>
+ *
+ * <p>If <code>Foo</code>&#x2019;s implementation of {@link
+ * StateEditable} considers the name as part of the editable state,
+ * the user can now choose &#x201c;Undo Name Change&#x201d; or
+ * &#x201c;Redo Name Change&#x201d; from the respective menu. No
+ * further undo support is needed from the application.
+ *
+ * <p>The following explains what happens in the example.
+ *
+ * <p><ol><li>When a <code>StateEdit</code> is created, the associated
+ * {@link StateEditable} gets asked to store its state into a hash
+ * table, {@link #preState}.</li>
+ *
+ * <li>The application will now perform some changes to the edited
+ * object.  This typically happens by invoking methods on the edited
+ * object.</li>
+ *
+ * <li>The editing phase is terminated by invoking the {@link #end()}
+ * method of the <code>StateEdit</code>. The <code>end()</code> method
+ * does two things.
+ *
+ *   <ul><li>The edited object receives a second request for storing
+ *   its state.  This time, it will use a different hash table, {@link
+ *   #postState}.</li>
+ *
+ *   <li>To increase efficiency, the <code>StateEdit</code> now removes
+ *   any entries from {@link #preState} and {@link #postState} that have
+ *   the same key, and whose values are equal. Equality is determined
+ *   by invoking the <code>equals</code> method inherited from
+ *   {@link java.lang.Object}.</li></ul></li>
+ *
+ * <li>When the user later chooses to undo the <code>StateEdit</code>,
+ * the edited object is asked to {@linkplain StateEditable#restoreState
+ * restore its state} from the {@link #preState} table.  Similarly,
+ * when the user chooses to <i>redo</i> the <code>StateEdit</code>,
+ * the edited object gets asked to restore its state from the {@link
+ * #postState}.</li></ol>
+ *
+ * @author Andrew Selkirk (aselkirk@sympatico.ca)
+ * @author Sascha Brawer (brawer@dandelis.ch)
  */
-public class StateEdit extends AbstractUndoableEdit
+public class StateEdit
+  extends AbstractUndoableEdit
 {
-
-  //-------------------------------------------------------------
-  // Variables --------------------------------------------------
-  //-------------------------------------------------------------
-
   /**
-   * RCSID
+   * The ID of the Java source file in Sun&#x2019;s Revision Control
+   * System (RCS).  This certainly should not be part of the API
+   * specification. But in order to be API-compatible with
+   * Sun&#x2019;s reference implementation, GNU Classpath also has to
+   * provide this field. However, we do not try to match its value.
    */
-  protected static final String RCSID = ""; // TODO
+  protected static final String RCSID = "";
+
 
   /**
-   * object
+   * The object which is being edited by this <code>StateEdit</code>.
    */
   protected StateEditable object;
 
+
   /**
-   * preState
+   * The state of <code>object</code> at the time of constructing
+   * this <code>StateEdit</code>.
    */
   protected Hashtable preState;
 
+
   /**
-   * postState
+   * The state of <code>object</code> at the time when {@link #end()}
+   * was called.
    */
   protected Hashtable postState;
 
+
   /**
-   * undoRedoName
+   * A human-readable name for this edit action.
    */
   protected String undoRedoName;
 
 
-  //-------------------------------------------------------------
-  // Initialization ---------------------------------------------
-  //-------------------------------------------------------------
-
   /**
-   * Constructor StateEdit
-   * @param obj Object to edit
+   * Constructs a <code>StateEdit</code>, specifying the object whose
+   * state is being edited.
+   *
+   * @param obj the object whose state is being edited by this
+   * <code>StateEdit</code>.
    */
   public StateEdit(StateEditable obj)
   {
     init(obj, null);
   }
 
+
   /**
-   * Constructor StateEdit
-   * @param obj Object to edit
-   * @param name Presentation name
+   * Constructs a <code>StateEdit</code>, specifying the object whose
+   * state is being edited.
+   *
+   * @param obj the object whose state is being edited by this
+   * <code>StateEdit</code>.
+   *
+   * @param name the human-readable name of the editing action.
    */
   public StateEdit(StateEditable obj, String name)
   {
@@ -102,14 +161,13 @@ public class StateEdit extends AbstractUndoableEdit
   }
 
 
-  //-------------------------------------------------------------
-  // Methods ----------------------------------------------------
-  //-------------------------------------------------------------
-
   /**
-   * Initialize this object.
-   * @param obj Object to edit
-   * @param name Presentation name
+   * Initializes this <code>StateEdit</code>. The edited object will
+   * be asked to store its current state into {@link #preState}.
+   *
+   * @param obj the object being edited.
+   *
+   * @param name the human-readable name of the editing action.
    */
   protected void init(StateEditable obj, String name)
   {
@@ -120,9 +178,12 @@ public class StateEdit extends AbstractUndoableEdit
     obj.storeState(preState);
   }
 
+
   /**
-   * Indicate that all edits are finished, and update this object
-   * with final state.
+   * Informs this <code>StateEdit</code> that all edits are finished.
+   * The edited object will be asked to store its state into {@link
+   * #postState}, and any redundant entries will get removed from
+   * {@link #preState} and {@link #postState}.
    */
   public void end()
   {
@@ -130,33 +191,56 @@ public class StateEdit extends AbstractUndoableEdit
     removeRedundantState();
   }
 
+
   /**
-   * Undo this edit by applying the initial state to the edited object.
+   * Undoes this edit operation. The edited object will be asked to
+   * {@linkplain StateEditable#restoreState restore its state} from
+   * {@link #preState}.
+   *
+   * @throws CannotUndoException if {@link #canUndo()} returns
+   * <code>false</code>, for example because this action has already
+   * been undone.
    */
   public void undo()
   {
+    super.undo();
     object.restoreState(preState);
   }
 
+
   /**
-   * Undo this edit by applying the final state to the edited object.
+   * Redoes this edit operation. The edited object will be asked to
+   * {@linkplain StateEditable#restoreState restore its state} from
+   * {@link #postState}.
+   *
+   * @throws CannotRedoException if {@link #canRedo()} returns
+   * <code>false</code>, for example because this action has not yet
+   * been undone.
    */
   public void redo()
   {
+    super.redo();
     object.restoreState(postState);
   }
 
+
   /**
-   * Return the presentation name of this object.
-   * @returns The name, or null if not set
+   * Returns a human-readable, localized name that describes this
+   * editing action and can be displayed to the user.
+   *
+   * @return the name, or <code>null</code> if no presentation
+   * name is available.
    */
   public String getPresentationName()
   {
     return undoRedoName;
   }
 
+
   /**
-   * removeRedundantState
+   * Removes all redundant entries from the pre- and post-edit state
+   * hash tables. An entry is considered redundant if it is present
+   * both before and after the edit, and if the two values are equal.
    */
   protected void removeRedundantState()
   {
index 016a54371d7b13902b3785498e4c67fa71e3b228..d3f9d4c37381e59ada7a7e8e4706007a7efe549a 100644 (file)
@@ -1,4 +1,4 @@
-/* StateEditable.java --
+/* StateEditable.java -- Interface for collaborating with StateEdit.
    Copyright (C) 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
@@ -37,29 +37,76 @@ exception statement from your version. */
 
 package javax.swing.undo;
 
-// Imports
 import java.util.Hashtable;
 
+
 /**
- * StateEditable public interface
- * @author Andrew Selkirk
+ * The interface for objects whose state can be undone or redone by a
+ * {@link StateEdit} action.
+ *
+ * <p>The following example shows how to write a class that implements
+ * this interface.
+ *
+ * <pre> class Foo
+ *   implements StateEditable
+ * {
+ *   private String name;
+ *
+ *   public void setName(String n) { name = n; }
+ *
+ *   public void restoreState(Hashtable h)
+ *   {
+ *     if (h.containsKey("name"))
+ *       setName((String) h.get("name"));
+ *   }
+ *
+ *   public void storeState(Hashtable s)
+ *   {
+ *     s.put("name", name);
+ *   }
+ * }</pre>
+ *
+ * @see StateEdit
+ *
+ * @author Andrew Selkirk (aselkirk@sympatico.ca)
+ * @author Sascha Brawer (brawer@dandelis.ch)
  */
 public interface StateEditable
 {
   /**
-   * Restore State
-   * @param state State
+   * The ID of the Java source file in Sun&#x2019;s Revision Control
+   * System (RCS).  This certainly should not be part of the API
+   * specification. But in order to be API-compatible with
+   * Sun&#x2019;s reference implementation, GNU Classpath also has to
+   * provide this field. However, we do not try to match its value.
    */
-  void restoreState(Hashtable state);
+  static final String RCSID = "";
+
 
   /**
-   * Store State
-   * @param state State
+   * Performs an edit action, taking any editable state information
+   * from the specified hash table.
+   *
+   * <p><b>Note to implementors of this interface:</b> To increase
+   * efficiency, the <code>StateEdit</code> class {@linkplan
+   * StateEdit#removeRedundantState() removes redundant state
+   * information}. Therefore, implementations of this interface must be
+   * prepared for the case where certain keys were stored into the
+   * table by {@link #storeState}, but are not present anymore
+   * when the <code>restoreState</code> method gets called.
+   *
+   * @param state a hash table containing the relevant state
+   * information.
    */
-  void storeState(Hashtable state);
+  void restoreState(Hashtable state);
+
 
   /**
-   * For some reason, Sun made the RCS IDs visible.
+   * Stores any editable state information into the specified hash
+   * table.
+   *
+   * @param state a hash table for storing relevant state
+   * information.
    */
-  String RCSID = "We aren't compatible";
-} // StateEditable
+  void storeState(Hashtable state);
+}