Commit aef81a9a by Sascha Brawer Committed by Michael Koch

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
parent 034f2316
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.
......
/* 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. */ ...@@ -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
* 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() 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.
*
* @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 alive && hasBeenDone;
return true; }
return false;
} // canRedo()
/** /**
* canUndo() * Redoes this editing action.
* @returns true if undoable, false otherwise *
* @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) if (!canRedo())
return true; throw new CannotRedoException();
return false; hasBeenDone = true;
} // canUndo() }
/** /**
* 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; return alive && !hasBeenDone;
} // die() }
/** /**
* getPresentation * Informs this edit action that it will no longer be used. Some
* @returns TODO * 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 ""; alive = false;
} // getPresentationName() }
/** /**
* getRedoPresentationName * 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 getRedoPresentationName() public boolean addEdit(UndoableEdit edit)
{ {
if (getPresentationName().equals("")) return false;
return RedoName; }
return RedoName + " " + getPresentationName();
} // getRedoPresentationName()
/** /**
* getUndoPresentationName * 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 getUndoPresentationName() public boolean replaceEdit(UndoableEdit edit)
{ {
if (getPresentationName().equals("")) return false;
return UndoName; }
return UndoName + " " + getPresentationName();
} // getUndoPresentationName()
/** /**
* isSignificant * Determines whether this editing action is significant enough for
* @returns true * 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() 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 * Calculates a localized name for presenting the undo action to the
* @param anEdit TODO * user.
* @returns TODO *
* <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; String msg, pres;
} // replaceEdit()
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 * Calculates a localized name for presenting the redo action to the
* @returns String representation * 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 String msg, pres;
+ " alive: " + alive);
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 public String toString()
* @throws CannotUndoException TODO
*/
public void undo() throws CannotUndoException
{ {
if (! canUndo()) return super.toString()
throw new CannotUndoException(); + " hasBeenDone: " + hasBeenDone
hasBeenDone = false; + " alive: " + alive;
} // undo() }
} // AbstractUndoableEdit }
/* 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. */ ...@@ -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
/* 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. */ ...@@ -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
/* 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; ...@@ -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(); /**
* Indicates whether the creation of this CompoundEdit is still in
/** * progress. Initially, the value of this flag is
* TODO * <code>true</code>. The {@link #end()} method changes the flag to
*/ * <code>false</code>.
private boolean inProgress = false; */
private boolean inProgress;
//-------------------------------------------------------------
// Initialization --------------------------------------------- /**
//------------------------------------------------------------- * Constructs a new CompoundEdit.
*/
/** public CompoundEdit()
* Create new Compound Edit {
*/ edits = new Vector();
public CompoundEdit() { inProgress = true;
} // CompoundEdit() }
//------------------------------------------------------------- /**
// Interface: UndoableEdit ------------------------------------ * 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.
/** *
* addEdit * @throws CannotUndoException if {@link #canUndo()} returns
* @param anEdit TODO * <code>false</code>. This can happen if {@link #end()} has not
* @returns TODO * been called on this <code>CompoundEdit</code>, or if this edit
*/ * has already been undone.
public boolean addEdit(UndoableEdit anEdit) { *
* @see #canUndo()
// Variables * @see #redo()
UndoableEdit lastEdit; */
public void undo()
if (inProgress == true) { throws CannotUndoException
{
// Get Last Edit // AbstractUndoableEdit.undo() will throw a CannotUndoException if
lastEdit = lastEdit(); // canUndo returns false.
super.undo();
// Check for null
if (lastEdit != null) { for (int i = edits.size() - 1; i >= 0; i--)
((UndoableEdit) edits.elementAt(i)).undo();
if (lastEdit.addEdit(anEdit) == false) { }
if (lastEdit.replaceEdit(anEdit) == false) {
edits.add(anEdit);
} /**
} * Redoes all edits that are part of of this
* <code>CompoundEdit</code>. The compound elements will receive the
} // if: lastEdit * <code>undo</code> message in the same order as they were added.
*
return true; * @throws CannotRedoException if {@link #canRedo()} returns
* <code>false</code>. This can happen if {@link #end()} has not
} else { * been called on this <code>CompoundEdit</code>, or if this edit
return false; * has already been redone.
} *
} // addEdit() * @see #canRedo()
* @see #undo()
/** */
* canRedo public void redo()
* @returns TODO throws CannotRedoException
*/ {
public boolean canRedo() { // AbstractUndoableEdit.redo() will throw a CannotRedoException if
if (isInProgress() == true || super.canRedo() == false) { // canRedo returns false.
return false; super.redo();
}
return true; for (int i = 0; i < edits.size(); i++)
} // canRedo() ((UndoableEdit) edits.elementAt(i)).redo();
}
/**
* canUndo
* @returns TODO /**
*/ * Returns the the <code>UndoableEdit</code> that was last added to
public boolean canUndo() { * this compound.
if (isInProgress() == true || super.canUndo() == false) { */
return false; protected UndoableEdit lastEdit()
} {
return true; if (edits.size() == 0)
} // canUndo() return null;
else
/** return (UndoableEdit) edits.elementAt(edits.size() - 1);
* die }
*/
public void die() {
/**
// Variables * Informs this edit action, and all compound edits, that they will
int index; * no longer be used. Some actions might use this information to
UndoableEdit current; * release resources such as open files. Called by {@link
* UndoManager} before this action is removed from the edit queue.
// Loop through all contained UndoableEdits *
for (index = edits.size() - 1; index >= 0; index--) { * <p>The compound elements will receive the
current = (UndoableEdit) edits.elementAt(index); * <code>die</code> message in the reverse order of addition.
current.die(); */
} // for: index public void die()
{
} // die() for (int i = edits.size() - 1; i >= 0; i--)
((UndoableEdit) edits.elementAt(i)).die();
/**
* end super.die();
*/ }
public void end() {
inProgress = false;
} // end() /**
* Incorporates another editing action into this one, thus forming a
/** * combined edit.
* getPresentationName *
* @returns TODO * <p>If this edit&#x2019;s {@link #end()} method has been called
*/ * before, <code>false</code> is returned immediately. Otherwise,
public String getPresentationName() { * the {@linkplain #lastEdit() last added edit} is given the
if (edits.size() == 0) { * opportunity to {@linkplain UndoableEdit#addEdit(UndoableEdit)
return super.getPresentationName(); * incorporate} <code>edit</code>. If this fails, <code>edit</code>
} else { * is given the opportunity to {@linkplain
return lastEdit().getPresentationName(); * UndoableEdit#replaceEdit(UndoableEdit) replace} the last added
} * edit. If this fails as well, <code>edit</code> gets added as a
} // getPresentationName() * new compound to {@link #edits}.
*
/** * @param edit the editing action being added.
* getRedoPresentationName *
* @returns TODO * @return <code>true</code> if <code>edit</code> could somehow be
*/ * incorporated; <code>false</code> if <code>edit</code> has not
public String getRedoPresentationName() { * been incorporated because {@link #end()} was called before.
if (edits.size() == 0) { */
return super.getRedoPresentationName(); public boolean addEdit(UndoableEdit edit)
} else { {
return lastEdit().getRedoPresentationName(); UndoableEdit last;
}
} // getRedoPresentationName() // If end has been called before, do nothing.
if (!inProgress)
/** return false;
* getUndoPresentationName
* @returns TODO last = lastEdit();
*/
public String getUndoPresentationName() { // If edit is the very first edit, just add it to the list.
if (edits.size() == 0) { if (last == null)
return super.getUndoPresentationName(); {
} else { edits.add(edit);
return lastEdit().getUndoPresentationName(); return true;
} }
} // getUndoPresentationName()
// Try to incorporate edit into last.
/** if (last.addEdit(edit))
* isInProgress return true;
* @returns TODO
*/ // Try to replace last by edit.
public boolean isInProgress() { if (edit.replaceEdit(last))
return inProgress; {
} // isInProgress() edits.set(edits.size() - 1, edit);
return true;
}
/**
* isSignigicant // If everything else has failed, add edit to the list of compound
* @returns TODO // edits.
*/ edits.add(edit);
public boolean isSignificant() { return true;
}
// Variables
int index;
UndoableEdit current; /**
* Informs this <code>CompoundEdit</code> that its construction
// Check each edit * phase has been completed. After this method has been called,
for (index = 0; index < edits.size(); index++) { * {@link #undo()} and {@link #redo()} may be called, {@link
current = (UndoableEdit) edits.elementAt(index); * #isInProgress()} will return <code>false</code>, and all attempts
if (current.isSignificant() == true) { * to {@linkplain #addEdit(UndoableEdit) add further edits} will
return true; * fail.
} */
} // for: index public void end()
{
return false; inProgress = false;
}
} // isSignificant()
/** /**
* lastEdit * Determines whether it would be possible to undo this editing
* @returns TODO * action. The result will be <code>true</code> if {@link #end()}
*/ * has been called on this <code>CompoundEdit</code>, {@link #die()}
protected UndoableEdit lastEdit() { * has not yet been called, and the edit has not been undone
if (edits.size() == 0) { * already.
return null; *
} * @return <code>true</code> to indicate that this action can be
return (UndoableEdit) edits.elementAt(edits.size() - 1); * undone; <code>false</code> otherwise.
} // lastEdit() *
* @see #undo()
/** * @see #canRedo()
* redo */
* @throws CannotRedoException TODO public boolean canUndo()
*/ {
public void redo() throws CannotRedoException { return !inProgress && super.canUndo();
}
// Variables
int index;
UndoableEdit current; /**
* Determines whether it would be possible to redo this editing
// Loop through all contained UndoableEdits * action. The result will be <code>true</code> if {@link #end()}
for (index = 0; index < edits.size(); index++) { * has been called on this <code>CompoundEdit</code>, {@link #die()}
current = (UndoableEdit) edits.elementAt(index); * has not yet been called, and the edit has not been redone
current.redo(); * already.
} // for: index *
* @return <code>true</code> to indicate that this action can be
} // redo() * redone; <code>false</code> otherwise.
*
/** * @see #redo()
* String representation * @see #canUndo()
* @returns String representation */
*/ public boolean canRedo()
public String toString() { {
return null; // TODO return !inProgress && super.canRedo();
} // toString() }
/**
* undo /**
* @throws CannotUndoException TODO * Determines whether the initial construction phase of this
*/ * <code>CompoundEdit</code> is still in progress. During this
public void undo() throws CannotUndoException { * phase, edits {@linkplain #addEdit(UndoableEdit) may be
* added}. After initialization has been terminated by calling
// Variables * {@link #end()}, {@link #undo()} and {@link #redo()} can be used.
int index; *
UndoableEdit current; * @return <code>true</code> if the initialization phase is still in
* progress; <code>false</code> if {@link #end()} has been called.
// Loop through all contained UndoableEdits *
for (index = edits.size() - 1; index >= 0; index--) { * @see #end()
current = (UndoableEdit) edits.elementAt(index); */
current.undo(); public boolean isInProgress()
} // for: index {
return inProgress;
} // undo() }
} // CompoundEdit /**
* 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;
}
}
/* 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; ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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()
{ {
......
/* 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. */ ...@@ -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.
*/ */
void restoreState(Hashtable state); static final String RCSID = "";
/** /**
* Store State * Performs an edit action, taking any editable state information
* @param state State * 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"; void storeState(Hashtable state);
} // StateEditable }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment