StateEdit.java (getPresentationName): Docfix.

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
This commit is contained in:
Sascha Brawer 2003-11-26 23:23:40 +01:00 committed by Michael Koch
parent 034f23169e
commit aef81a9acb
7 changed files with 814 additions and 430 deletions

View 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> 2003-11-26 David Belanger <dbelan2@cs.mcgill.ca>
* java/util/zip/ZipFile (Zipfile(File)): Set file path as name. * java/util/zip/ZipFile (Zipfile(File)): Set file path as name.

View file

@ -1,4 +1,4 @@
/* AbstractTableModel.java -- /* AbstractUndoableEdit.java
Copyright (C) 2002, 2003 Free Software Foundation, Inc. Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
@ -39,180 +39,285 @@ exception statement from your version. */
package javax.swing.undo; package javax.swing.undo;
import java.io.Serializable; import java.io.Serializable;
import javax.swing.UIManager;
/** /**
* AbstractUndoableEdit * A default implementation of <code>UndoableEdit</code> that can be
* @author Andrew Selkirk * 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; 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
protected static final String RedoName = "Redo"; * 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
* String returned by getUndoPresentationName() * <code>&#x201c;AbstractUndoableEdit.undoText&#x201d;</code>.
*/ */
protected static final String UndoName = "Undo"; protected static final String UndoName = "Undo";
//-------------------------------------------------------------
// Variables --------------------------------------------------
//-------------------------------------------------------------
/** /**
* TODO * 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>.
*/ */
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 <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 alive = true; private boolean hasBeenDone;
//-------------------------------------------------------------
// Initialization ---------------------------------------------
//-------------------------------------------------------------
/** /**
* Create new AbstractUndoableEdit * 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;
/**
* 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() 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 * Undoes this editing action.
* @param anEdit TODO *
* @returns TODO * @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; if (!canUndo())
} // addEdit() throw new CannotUndoException();
hasBeenDone = false;
}
/** /**
* canRedo() * Determines whether it would be possible to undo this editing
* @returns true if redoable, false otherwise * action.
*/ *
public boolean canRedo() * @return <code>true</code> to indicate that this action can be
{ * undone, <code>false</code> otherwise.
if (alive == true && hasBeenDone == false) *
return true; * @see #undo()
return false; * @see #canRedo()
} // canRedo()
/**
* canUndo()
* @returns true if undoable, false otherwise
*/ */
public boolean canUndo() public boolean canUndo()
{ {
if (alive == true && hasBeenDone == true) return alive && hasBeenDone;
return true; }
return false;
} // canUndo()
/**
* 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 void redo()
throws CannotRedoException
{
if (!canRedo())
throw new CannotRedoException();
hasBeenDone = true;
}
/**
* 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 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() public void die()
{ {
alive = false; alive = false;
} // die() }
/** /**
* getPresentation * Incorporates another editing action into this one, thus forming a
* @returns TODO * 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 getPresentationName() public boolean addEdit(UndoableEdit edit)
{ {
return ""; return false;
} // getPresentationName() }
/** /**
* getRedoPresentationName * Incorporates another editing action into this one, thus forming a
* @returns TODO * 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 getRedoPresentationName() public boolean replaceEdit(UndoableEdit edit)
{ {
if (getPresentationName().equals("")) return false;
return RedoName; }
return RedoName + " " + getPresentationName();
} // getRedoPresentationName()
/** /**
* getUndoPresentationName * Determines whether this editing action is significant enough for
* @returns TODO * being seperately undoable by the user. A typical significant
*/ * action would be the resizing of an object. However, changing the
public String getUndoPresentationName() * selection in a text document would usually not be considered
{ * significant.
if (getPresentationName().equals("")) *
return UndoName; * <p>The default implementation returns <code>true</code>.
return UndoName + " " + getPresentationName(); *
} // getUndoPresentationName() * @return <code>true</code> to indicate that the action is
* significant enough for being separately undoable, or
/** * <code>false</code> otherwise.
* isSignificant
* @returns true
*/ */
public boolean isSignificant() public boolean isSignificant()
{ {
return true; return true;
} // isSignificant() }
/** /**
* redo * Returns a human-readable, localized name that describes this
* @throws CannotRedoException TODO * 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()) return "";
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);
} }
/** /**
* undo * Calculates a localized name for presenting the undo action to the
* @throws CannotUndoException TODO * 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 void undo() throws CannotUndoException public String getUndoPresentationName()
{ {
if (! canUndo()) String msg, pres;
throw new CannotUndoException();
hasBeenDone = false; msg = UIManager.getString("AbstractUndoableEdit.undoText");
} // undo() if (msg == null)
} // AbstractUndoableEdit 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.
*
* <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 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;
}
}

View file

@ -1,5 +1,5 @@
/* AbstractTableModel.java -- /* CannotRedoException.java
Copyright (C) 2002 Free Software Foundation, Inc. Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
@ -38,17 +38,19 @@ exception statement from your version. */
package javax.swing.undo; package javax.swing.undo;
/** /**
* CannotRedoException * An exception which indicates that an editing action cannot be
* @author Andrew Selkirk * redone.
*
* @author Andrew Selkirk (aselkirk@sympatico.ca)
* @author Sascha Brawer (brawer@dandelis.ch)
*/ */
public class CannotRedoException extends RuntimeException { public class CannotRedoException
extends RuntimeException
/** {
* Create exception /**
*/ * Constructs a new instance of a <code>CannotRedoException</code>.
public CannotRedoException() { */
super(); public CannotRedoException()
} // CannotRedoException() {
}
}
} // CannotRedoException

View file

@ -1,5 +1,5 @@
/* AbstractTableModel.java -- /* CannotUndoException.java
Copyright (C) 2002 Free Software Foundation, Inc. Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
@ -37,18 +37,21 @@ exception statement from your version. */
package javax.swing.undo; package javax.swing.undo;
/** /**
* CannotUndoException * An exception which indicates that an editing action cannot be
* @author Andrew Selkirk * undone.
*
* @author Andrew Selkirk (aselkirk@sympatico.ca)
* @author Sascha Brawer (brawer@dandelis.ch)
*/ */
public class CannotUndoException extends RuntimeException { public class CannotUndoException
extends RuntimeException
/** {
* Create exception /**
*/ * Constructs a new instance of a <code>CannotUndoException</code>.
public CannotUndoException() { */
super(); public CannotUndoException()
} // CannotUndoException() {
}
}
} // CannotUndoException

View file

@ -1,5 +1,5 @@
/* AbstractTableModel.java -- /* CompoundEdit.java -- Combines multiple UndoableEdits.
Copyright (C) 2002 Free Software Foundation, Inc. Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
@ -41,242 +41,352 @@ package javax.swing.undo;
import java.util.Vector; import java.util.Vector;
/** /**
* CompoundEdit * An editing action that consists of multiple
* @author Andrew Selkirk * <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 { public class CompoundEdit
extends AbstractUndoableEdit
//------------------------------------------------------------- {
// Variables -------------------------------------------------- /**
//------------------------------------------------------------- * The <code>UndoableEdit</code>s being combined into a compound
* editing action.
/** */
* The collection of UndoableEdits undone/redone en protected Vector edits;
* masse by this CompoundEdit
*/
protected Vector edits = new Vector();
/**
* TODO
*/
private boolean inProgress = false;
//------------------------------------------------------------- /**
// Initialization --------------------------------------------- * 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>.
* Create new Compound Edit */
*/ private boolean inProgress;
public CompoundEdit() {
} // CompoundEdit()
//------------------------------------------------------------- /**
// Interface: UndoableEdit ------------------------------------ * Constructs a new CompoundEdit.
//------------------------------------------------------------- */
public CompoundEdit()
{
edits = new Vector();
inProgress = true;
}
/** /**
* addEdit * Undoes all edits that are part of of this
* @param anEdit TODO * <code>CompoundEdit</code>. The compound elements will receive the
* @returns TODO * <code>undo</code> message in the reverse order of addition.
*/ *
public boolean addEdit(UndoableEdit anEdit) { * @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();
// Variables for (int i = edits.size() - 1; i >= 0; i--)
UndoableEdit lastEdit; ((UndoableEdit) edits.elementAt(i)).undo();
}
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 * Redoes all edits that are part of of this
* @returns TODO * <code>CompoundEdit</code>. The compound elements will receive the
*/ * <code>undo</code> message in the same order as they were added.
public boolean isSignificant() { *
* @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();
// Variables for (int i = 0; i < edits.size(); i++)
int index; ((UndoableEdit) edits.elementAt(i)).redo();
UndoableEdit current; }
// Check each edit
for (index = 0; index < edits.size(); index++) { /**
current = (UndoableEdit) edits.elementAt(index); * Returns the the <code>UndoableEdit</code> that was last added to
if (current.isSignificant() == true) { * this compound.
return true; */
} protected UndoableEdit lastEdit()
} // for: index {
if (edits.size() == 0)
return false; return null;
else
} // isSignificant() return (UndoableEdit) edits.elementAt(edits.size() - 1);
}
/**
* 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 /**
* 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;
}
}

View file

@ -1,4 +1,4 @@
/* StateEdit.java -- /* StateEdit.java -- UndoableEdit for StateEditable implementations.
Copyright (C) 2002, 2003 Free Software Foundation, Inc. Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
@ -42,59 +42,118 @@ import java.util.Hashtable;
import java.util.Iterator; import java.util.Iterator;
/** /**
* StateEdit * A helper class, making it easy to support undo and redo.
* @author Andrew Selkirk *
* <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; protected StateEditable object;
/** /**
* preState * The state of <code>object</code> at the time of constructing
* this <code>StateEdit</code>.
*/ */
protected Hashtable preState; protected Hashtable preState;
/** /**
* postState * The state of <code>object</code> at the time when {@link #end()}
* was called.
*/ */
protected Hashtable postState; protected Hashtable postState;
/** /**
* undoRedoName * A human-readable name for this edit action.
*/ */
protected String undoRedoName; protected String undoRedoName;
//-------------------------------------------------------------
// Initialization ---------------------------------------------
//-------------------------------------------------------------
/** /**
* Constructor StateEdit * Constructs a <code>StateEdit</code>, specifying the object whose
* @param obj Object to edit * state is being edited.
*
* @param obj the object whose state is being edited by this
* <code>StateEdit</code>.
*/ */
public StateEdit(StateEditable obj) public StateEdit(StateEditable obj)
{ {
init(obj, null); init(obj, null);
} }
/** /**
* Constructor StateEdit * Constructs a <code>StateEdit</code>, specifying the object whose
* @param obj Object to edit * state is being edited.
* @param name Presentation name *
* @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) public StateEdit(StateEditable obj, String name)
{ {
@ -102,14 +161,13 @@ public class StateEdit extends AbstractUndoableEdit
} }
//-------------------------------------------------------------
// Methods ----------------------------------------------------
//-------------------------------------------------------------
/** /**
* Initialize this object. * Initializes this <code>StateEdit</code>. The edited object will
* @param obj Object to edit * be asked to store its current state into {@link #preState}.
* @param name Presentation name *
* @param obj the object being edited.
*
* @param name the human-readable name of the editing action.
*/ */
protected void init(StateEditable obj, String name) protected void init(StateEditable obj, String name)
{ {
@ -120,9 +178,12 @@ public class StateEdit extends AbstractUndoableEdit
obj.storeState(preState); obj.storeState(preState);
} }
/** /**
* Indicate that all edits are finished, and update this object * Informs this <code>StateEdit</code> that all edits are finished.
* with final state. * 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() public void end()
{ {
@ -130,33 +191,56 @@ public class StateEdit extends AbstractUndoableEdit
removeRedundantState(); 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() public void undo()
{ {
super.undo();
object.restoreState(preState); 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() public void redo()
{ {
super.redo();
object.restoreState(postState); object.restoreState(postState);
} }
/** /**
* Return the presentation name of this object. * Returns a human-readable, localized name that describes this
* @returns The name, or null if not set * 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() public String getPresentationName()
{ {
return undoRedoName; 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() protected void removeRedundantState()
{ {

View file

@ -1,4 +1,4 @@
/* StateEditable.java -- /* StateEditable.java -- Interface for collaborating with StateEdit.
Copyright (C) 2002, 2003 Free Software Foundation, Inc. Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
@ -37,29 +37,76 @@ exception statement from your version. */
package javax.swing.undo; package javax.swing.undo;
// Imports
import java.util.Hashtable; import java.util.Hashtable;
/** /**
* StateEditable public interface * The interface for objects whose state can be undone or redone by a
* @author Andrew Selkirk * {@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 public interface StateEditable
{ {
/** /**
* Restore State * The ID of the Java source file in Sun&#x2019;s Revision Control
* @param state State * 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.
*/
static final String RCSID = "";
/**
* 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 restoreState(Hashtable state); 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"; void storeState(Hashtable state);
} // StateEditable }