From aef81a9acb17a9eadc5df75007b4364fbfa3a9de Mon Sep 17 00:00:00 2001 From: Sascha Brawer Date: Wed, 26 Nov 2003 23:23:40 +0100 Subject: [PATCH] StateEdit.java (getPresentationName): Docfix. 2003-11-26 Sascha Brawer * javax/swing/undo/StateEdit.java (getPresentationName): Docfix. * javax/swing/undo/AbstractUndoableEdit.java (canUndo, canRedo, isSignificant): Likewise. 2003-11-26 Sascha Brawer * 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 * javax/swing/undo/StateEdit.java: Re-format, document. (undo, redo): Also call inherited implementation. 2003-11-26 Sascha Brawer * javax/swing/undo/StateEditable.java: Re-format, document. 2003-11-26 Sascha Brawer * 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 | 33 + .../swing/undo/AbstractUndoableEdit.java | 345 +++++++---- .../javax/swing/undo/CannotRedoException.java | 32 +- .../javax/swing/undo/CannotUndoException.java | 33 +- libjava/javax/swing/undo/CompoundEdit.java | 566 +++++++++++------- libjava/javax/swing/undo/StateEdit.java | 160 +++-- libjava/javax/swing/undo/StateEditable.java | 75 ++- 7 files changed, 814 insertions(+), 430 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index bf2ffaeed691..d14bfdea90de 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,36 @@ +2003-11-26 Sascha Brawer + + * javax/swing/undo/StateEdit.java (getPresentationName): Docfix. + * javax/swing/undo/AbstractUndoableEdit.java (canUndo, canRedo, + isSignificant): Likewise. + +2003-11-26 Sascha Brawer + + * 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 + + * javax/swing/undo/StateEdit.java: Re-format, document. + (undo, redo): Also call inherited implementation. + +2003-11-26 Sascha Brawer + + * javax/swing/undo/StateEditable.java: Re-format, document. + +2003-11-26 Sascha Brawer + + * 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 * java/util/zip/ZipFile (Zipfile(File)): Set file path as name. diff --git a/libjava/javax/swing/undo/AbstractUndoableEdit.java b/libjava/javax/swing/undo/AbstractUndoableEdit.java index d845e4341bbe..e694c0a447f8 100644 --- a/libjava/javax/swing/undo/AbstractUndoableEdit.java +++ b/libjava/javax/swing/undo/AbstractUndoableEdit.java @@ -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 UndoableEdit 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 serialver + * 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() - */ - protected static final String RedoName = "Redo"; - - /** - * String returned by getUndoPresentationName() + * The constant string “Undo”, 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 + * “AbstractUndoableEdit.undoText”. */ protected static final String UndoName = "Undo"; - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - /** - * TODO + * The constant string “Redo”, 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 + * “AbstractUndoableEdit.redoText”. */ - private boolean hasBeenDone = false; + protected static final String RedoName = "Redo"; + /** - * The edit is alive + * Indicates whether this editing action has been executed. A value + * of true means that the action was performed, or that + * a redo operation was successful. A value of false + * means that the action has not yet performed, or that an undo + * operation was successful. */ - private boolean alive = true; + private boolean hasBeenDone; - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - /** - * Create new AbstractUndoableEdit + * Indicates whether this editing action is still alive. The value + * is set to true by the constructor, and to + * false by the {@link #die()} method. + */ + private boolean alive; + + + /** + * Constructs a new AbstractUndoableEdit. The initial + * state is that the editing action is alive, and + * hasBeenDone is true. */ 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 + * false, 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 - */ - public boolean canRedo() - { - if (alive == true && hasBeenDone == false) - return true; - return false; - } // canRedo() - - /** - * canUndo() - * @returns true if undoable, false otherwise + * Determines whether it would be possible to undo this editing + * action. + * + * @return true to indicate that this action can be + * undone, false otherwise. + * + * @see #undo() + * @see #canRedo() */ public boolean canUndo() { - if (alive == true && hasBeenDone == true) - return true; - return false; - } // canUndo() + return alive && hasBeenDone; + } + + + /** + * Redoes this editing action. + * + * @throws CannotRedoException if {@link #canRedo()} returns + * false, for example because this action has not + * yet been undone. + * + * @see #canRedo() + * @see #undo() + */ + public void redo() + throws CannotRedoException + { + if (!canRedo()) + throw new CannotRedoException(); + hasBeenDone = true; + } + + + /** + * Determines whether it would be possible to redo this editing + * action. + * + * @return true to indicate that this action can be + * redone, false otherwise. + * + * @see #redo() + * @see #canUndo() + */ + public boolean canRedo() + { + return alive && !hasBeenDone; + } + /** - * die + * 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 void die() { alive = false; - } // die() + } + /** - * getPresentation - * @returns TODO + * Incorporates another editing action into this one, thus forming a + * combined action. + * + *

The default implementation always returns false, + * indicating that the editing action could not be incorporated. + * + * @param edit the editing action to be incorporated. */ - public String getPresentationName() + public boolean addEdit(UndoableEdit edit) { - return ""; - } // getPresentationName() - + return false; + } + + /** - * getRedoPresentationName - * @returns TODO + * Incorporates another editing action into this one, thus forming a + * combined action that replaces the argument action. + * + *

The default implementation always returns false, + * indicating that the argument action should not be replaced. + * + * @param edit the editing action to be replaced. */ - public String getRedoPresentationName() + public boolean replaceEdit(UndoableEdit edit) { - if (getPresentationName().equals("")) - return RedoName; - return RedoName + " " + getPresentationName(); - } // getRedoPresentationName() - + return false; + } + + /** - * getUndoPresentationName - * @returns TODO - */ - public String getUndoPresentationName() - { - if (getPresentationName().equals("")) - return UndoName; - return UndoName + " " + getPresentationName(); - } // getUndoPresentationName() - - /** - * 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. + * + *

The default implementation returns true. + * + * @return true to indicate that the action is + * significant enough for being separately undoable, or + * false 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. + * + *

The default implementation returns an empty string. */ - public void redo() throws CannotRedoException + public String getPresentationName() { - if (! canRedo()) - throw new CannotRedoException(); - hasBeenDone = true; - } // redo() - - /** - * replaceEdit - * @param anEdit TODO - * @returns TODO - */ - public boolean replaceEdit(UndoableEdit anEdit) - { - return false; - } // replaceEdit() - - /** - * String representation - * @returns String representation - */ - public String toString() - { - return (super.toString() + " hasBeenDone: " + hasBeenDone - + " alive: " + alive); + return ""; } + /** - * undo - * @throws CannotUndoException TODO + * Calculates a localized name for presenting the undo action to the + * user. + * + *

The default implementation returns the concatenation of the + * string “Undo” and the action name, which is + * determined by calling {@link #getPresentationName()}. + * + *

The string “Undo” is retrieved from the {@link + * javax.swing.UIManager}, using the key + * “AbstractUndoableEdit.undoText”. This + * allows the text to be localized. */ - public void undo() throws CannotUndoException + public String getUndoPresentationName() { - if (! canUndo()) - throw new CannotUndoException(); - hasBeenDone = false; - } // undo() -} // AbstractUndoableEdit + 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; + } + + + /** + * Calculates a localized name for presenting the redo action to the + * user. + * + *

The default implementation returns the concatenation of the + * string “Redo” and the action name, which is + * determined by calling {@link #getPresentationName()}. + * + *

The string “Redo” is retrieved from the {@link + * javax.swing.UIManager}, using the key + * “AbstractUndoableEdit.redoText”. This + * allows the text to be localized. + */ + public String getRedoPresentationName() + { + 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; + } + + + public String toString() + { + return super.toString() + + " hasBeenDone: " + hasBeenDone + + " alive: " + alive; + } +} diff --git a/libjava/javax/swing/undo/CannotRedoException.java b/libjava/javax/swing/undo/CannotRedoException.java index 030975d4f1de..f482b75bb979 100644 --- a/libjava/javax/swing/undo/CannotRedoException.java +++ b/libjava/javax/swing/undo/CannotRedoException.java @@ -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 CannotRedoException. + */ + public CannotRedoException() + { + } +} diff --git a/libjava/javax/swing/undo/CannotUndoException.java b/libjava/javax/swing/undo/CannotUndoException.java index c039d1bbebd1..0193921ed192 100644 --- a/libjava/javax/swing/undo/CannotUndoException.java +++ b/libjava/javax/swing/undo/CannotUndoException.java @@ -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 CannotUndoException. + */ + public CannotUndoException() + { + } +} diff --git a/libjava/javax/swing/undo/CompoundEdit.java b/libjava/javax/swing/undo/CompoundEdit.java index be612dad77b7..12ff2bd36ec9 100644 --- a/libjava/javax/swing/undo/CompoundEdit.java +++ b/libjava/javax/swing/undo/CompoundEdit.java @@ -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 + * UndoableEdits. + * + *

The use of a CompoundEdit is divided in two separate + * phases. + * + *

  1. In the first phase, the CompoundEdit is + * initialized. After a new instance of CompoundEdit has + * been created, {@link #addEdit(UndoableEdit)} is called for each + * element of the compound. To terminate the initialization phase, + * call {@link #end()}.
  2. + * + *
  3. In the second phase, the the CompoundEdit can be + * used, typically by invoking {@link #undo()} and {@link + * #redo()}.
+ * + * @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; +public class CompoundEdit + extends AbstractUndoableEdit +{ + /** + * The UndoableEdits being combined into a compound + * editing action. + */ + protected Vector edits; - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Create new Compound Edit - */ - public CompoundEdit() { - } // CompoundEdit() + /** + * Indicates whether the creation of this CompoundEdit is still in + * progress. Initially, the value of this flag is + * true. The {@link #end()} method changes the flag to + * false. + */ + private boolean inProgress; - //------------------------------------------------------------- - // Interface: UndoableEdit ------------------------------------ - //------------------------------------------------------------- + /** + * Constructs a new CompoundEdit. + */ + public CompoundEdit() + { + edits = new Vector(); + inProgress = true; + } + - /** - * addEdit - * @param anEdit TODO - * @returns TODO - */ - public boolean addEdit(UndoableEdit anEdit) { + /** + * Undoes all edits that are part of of this + * CompoundEdit. The compound elements will receive the + * undo message in the reverse order of addition. + * + * @throws CannotUndoException if {@link #canUndo()} returns + * false. This can happen if {@link #end()} has not + * been called on this CompoundEdit, 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(); - // 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() + for (int i = edits.size() - 1; i >= 0; i--) + ((UndoableEdit) edits.elementAt(i)).undo(); + } - /** - * isSignigicant - * @returns TODO - */ - public boolean isSignificant() { + /** + * Redoes all edits that are part of of this + * CompoundEdit. The compound elements will receive the + * undo message in the same order as they were added. + * + * @throws CannotRedoException if {@link #canRedo()} returns + * false. This can happen if {@link #end()} has not + * been called on this CompoundEdit, 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(); - // Variables - int index; - UndoableEdit current; + for (int i = 0; i < edits.size(); i++) + ((UndoableEdit) edits.elementAt(i)).redo(); + } - // 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() + + /** + * Returns the the UndoableEdit that was last added to + * this compound. + */ + protected UndoableEdit lastEdit() + { + if (edits.size() == 0) + return null; + else + return (UndoableEdit) edits.elementAt(edits.size() - 1); + } -} // CompoundEdit + /** + * 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. + * + *

The compound elements will receive the + * die 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. + * + *

If this edit’s {@link #end()} method has been called + * before, false is returned immediately. Otherwise, + * the {@linkplain #lastEdit() last added edit} is given the + * opportunity to {@linkplain UndoableEdit#addEdit(UndoableEdit) + * incorporate} edit. If this fails, edit + * is given the opportunity to {@linkplain + * UndoableEdit#replaceEdit(UndoableEdit) replace} the last added + * edit. If this fails as well, edit gets added as a + * new compound to {@link #edits}. + * + * @param edit the editing action being added. + * + * @return true if edit could somehow be + * incorporated; false if edit 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 CompoundEdit 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 false, 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 true if {@link #end()} + * has been called on this CompoundEdit, {@link #die()} + * has not yet been called, and the edit has not been undone + * already. + * + * @return true to indicate that this action can be + * undone; false 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 true if {@link #end()} + * has been called on this CompoundEdit, {@link #die()} + * has not yet been called, and the edit has not been redone + * already. + * + * @return true to indicate that this action can be + * redone; false otherwise. + * + * @see #redo() + * @see #canUndo() + */ + public boolean canRedo() + { + return !inProgress && super.canRedo(); + } + + + /** + * Determines whether the initial construction phase of this + * CompoundEdit 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 true if the initialization phase is still in + * progress; false 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. + * + *

A CompoundEdit 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. + * + *

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. + * + *

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. + * + *

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; + } +} diff --git a/libjava/javax/swing/undo/StateEdit.java b/libjava/javax/swing/undo/StateEdit.java index 6a32fbdb48d1..00f1e2d830c4 100644 --- a/libjava/javax/swing/undo/StateEdit.java +++ b/libjava/javax/swing/undo/StateEdit.java @@ -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. + * + *

The following example shows how to use this class. + * + *

  Foo foo; // class Foo implements {@link StateEditable}
+ *  StateEdit edit;
+ *
+ *  edit = new StateEdit(foo, "Name Change");
+ *  foo.setName("Jane Doe");
+ *  edit.end();
+ *  undoManager.addEdit(edit);
+ * + *

If Foo’s implementation of {@link + * StateEditable} considers the name as part of the editable state, + * the user can now choose “Undo Name Change” or + * “Redo Name Change” from the respective menu. No + * further undo support is needed from the application. + * + *

The following explains what happens in the example. + * + *

  1. When a StateEdit is created, the associated + * {@link StateEditable} gets asked to store its state into a hash + * table, {@link #preState}.
  2. + * + *
  3. The application will now perform some changes to the edited + * object. This typically happens by invoking methods on the edited + * object.
  4. + * + *
  5. The editing phase is terminated by invoking the {@link #end()} + * method of the StateEdit. The end() method + * does two things. + * + *
    • The edited object receives a second request for storing + * its state. This time, it will use a different hash table, {@link + * #postState}.
    • + * + *
    • To increase efficiency, the StateEdit 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 equals method inherited from + * {@link java.lang.Object}.
  6. + * + *
  7. When the user later chooses to undo the StateEdit, + * the edited object is asked to {@linkplain StateEditable#restoreState + * restore its state} from the {@link #preState} table. Similarly, + * when the user chooses to redo the StateEdit, + * the edited object gets asked to restore its state from the {@link + * #postState}.
+ * + * @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’s Revision Control + * System (RCS). This certainly should not be part of the API + * specification. But in order to be API-compatible with + * Sun’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 StateEdit. */ protected StateEditable object; + /** - * preState + * The state of object at the time of constructing + * this StateEdit. */ protected Hashtable preState; + /** - * postState + * The state of object 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 StateEdit, specifying the object whose + * state is being edited. + * + * @param obj the object whose state is being edited by this + * StateEdit. */ public StateEdit(StateEditable obj) { init(obj, null); } + /** - * Constructor StateEdit - * @param obj Object to edit - * @param name Presentation name + * Constructs a StateEdit, specifying the object whose + * state is being edited. + * + * @param obj the object whose state is being edited by this + * StateEdit. + * + * @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 StateEdit. 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 StateEdit 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 + * false, 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 + * false, 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 null 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() { diff --git a/libjava/javax/swing/undo/StateEditable.java b/libjava/javax/swing/undo/StateEditable.java index 016a54371d7b..d3f9d4c37381 100644 --- a/libjava/javax/swing/undo/StateEditable.java +++ b/libjava/javax/swing/undo/StateEditable.java @@ -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. + * + *

The following example shows how to write a class that implements + * this interface. + * + *

 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);
+ *   }
+ * }
+ * + * @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’s Revision Control + * System (RCS). This certainly should not be part of the API + * specification. But in order to be API-compatible with + * Sun’s reference implementation, GNU Classpath also has to + * provide this field. However, we do not try to match its value. + */ + static final String RCSID = ""; + + + /** + * Performs an edit action, taking any editable state information + * from the specified hash table. + * + *

Note to implementors of this interface: To increase + * efficiency, the StateEdit 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 restoreState method gets called. + * + * @param state a hash table containing the relevant state + * information. */ void restoreState(Hashtable state); - /** - * Store State - * @param state State - */ - void storeState(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); +}