summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/undo
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/undo')
-rw-r--r--libjava/classpath/javax/swing/undo/AbstractUndoableEdit.java323
-rw-r--r--libjava/classpath/javax/swing/undo/CannotRedoException.java56
-rw-r--r--libjava/classpath/javax/swing/undo/CannotUndoException.java58
-rw-r--r--libjava/classpath/javax/swing/undo/CompoundEdit.java400
-rw-r--r--libjava/classpath/javax/swing/undo/StateEdit.java265
-rw-r--r--libjava/classpath/javax/swing/undo/StateEditable.java114
-rw-r--r--libjava/classpath/javax/swing/undo/UndoManager.java625
-rw-r--r--libjava/classpath/javax/swing/undo/UndoableEdit.java157
-rw-r--r--libjava/classpath/javax/swing/undo/UndoableEditSupport.java272
-rw-r--r--libjava/classpath/javax/swing/undo/package.html46
10 files changed, 2316 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/undo/AbstractUndoableEdit.java b/libjava/classpath/javax/swing/undo/AbstractUndoableEdit.java
new file mode 100644
index 000000000..fc586604a
--- /dev/null
+++ b/libjava/classpath/javax/swing/undo/AbstractUndoableEdit.java
@@ -0,0 +1,323 @@
+/* AbstractUndoableEdit.java --
+ Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.undo;
+
+import java.io.Serializable;
+
+import javax.swing.UIManager;
+
+/**
+ * A default implementation of <code>UndoableEdit</code> that can be
+ * used as a base for implementing editing operations.
+ *
+ * @author Andrew Selkirk (aselkirk@sympatico.ca)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class AbstractUndoableEdit
+ implements UndoableEdit, Serializable
+{
+ /**
+ * 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;
+
+
+ /**
+ * 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 UndoName = "Undo";
+
+
+ /**
+ * 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 RedoName = "Redo";
+
+
+ /**
+ * 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;
+
+
+ /**
+ * 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()
+ {
+ // The API specification is not clear, but Mauve test code has
+ // determined that hasBeenDone is initially set to true.
+ alive = hasBeenDone = true;
+ }
+
+
+ /**
+ * Undoes this editing action.
+ *
+ * @throws CannotUndoException if {@link #canUndo()} returns
+ * <code>false</code>, for example because this action has already
+ * been undone.
+ *
+ * @see #canUndo()
+ * @see #redo()
+ */
+ public void undo()
+ throws CannotUndoException
+ {
+ if (!canUndo())
+ throw new CannotUndoException();
+ hasBeenDone = false;
+ }
+
+
+ /**
+ * Determines whether it would be possible to undo this editing
+ * action.
+ *
+ * @return <code>true</code> to indicate that this action can be
+ * undone, <code>false</code> otherwise.
+ *
+ * @see #undo()
+ * @see #canRedo()
+ */
+ public boolean canUndo()
+ {
+ return alive && hasBeenDone;
+ }
+
+
+ /**
+ * 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;
+ }
+
+
+ /**
+ * 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;
+ }
+
+
+ /**
+ * Incorporates another editing action into this one, thus forming a
+ * combined action.
+ *
+ * <p>The default implementation always returns <code>false</code>,
+ * indicating that the editing action could not be incorporated.
+ *
+ * @param edit the editing action to be incorporated.
+ */
+ public boolean addEdit(UndoableEdit edit)
+ {
+ return false;
+ }
+
+
+ /**
+ * Incorporates another editing action into this one, thus forming a
+ * combined action that replaces the argument action.
+ *
+ * <p>The default implementation always returns <code>false</code>,
+ * indicating that the argument action should not be replaced.
+ *
+ * @param edit the editing action to be replaced.
+ */
+ public boolean replaceEdit(UndoableEdit edit)
+ {
+ return false;
+ }
+
+
+ /**
+ * Determines whether this editing action is significant enough for
+ * being seperately undoable by the user. A typical significant
+ * action would be the resizing of an object. However, changing the
+ * selection in a text document would usually not be considered
+ * significant.
+ *
+ * <p>The default implementation returns <code>true</code>.
+ *
+ * @return <code>true</code> to indicate that the action is
+ * significant enough for being separately undoable, or
+ * <code>false</code> otherwise.
+ */
+ public boolean isSignificant()
+ {
+ return true;
+ }
+
+
+ /**
+ * Returns a human-readable, localized name that describes this
+ * editing action and can be displayed to the user.
+ *
+ * <p>The default implementation returns an empty string.
+ */
+ public String getPresentationName()
+ {
+ return "";
+ }
+
+
+ /**
+ * Calculates a localized name for presenting the undo action to the
+ * user.
+ *
+ * <p>The default implementation returns the concatenation of the
+ * string &#x201c;Undo&#x201d; and the action name, which is
+ * determined by calling {@link #getPresentationName()}.
+ *
+ * <p>The string &#x201c;Undo&#x201d; is retrieved from the {@link
+ * javax.swing.UIManager}, using the key
+ * <code>&#x201c;AbstractUndoableEdit.undoText&#x201d;</code>. This
+ * allows the text to be localized.
+ */
+ public String getUndoPresentationName()
+ {
+ 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.
+ *
+ * <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;
+ }
+}
diff --git a/libjava/classpath/javax/swing/undo/CannotRedoException.java b/libjava/classpath/javax/swing/undo/CannotRedoException.java
new file mode 100644
index 000000000..5f2264835
--- /dev/null
+++ b/libjava/classpath/javax/swing/undo/CannotRedoException.java
@@ -0,0 +1,56 @@
+/* CannotRedoException.java
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.undo;
+
+/**
+ * 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
+{
+ /**
+ * Constructs a new instance of a <code>CannotRedoException</code>.
+ */
+ public CannotRedoException()
+ {
+ super();
+ }
+}
diff --git a/libjava/classpath/javax/swing/undo/CannotUndoException.java b/libjava/classpath/javax/swing/undo/CannotUndoException.java
new file mode 100644
index 000000000..8d08cda68
--- /dev/null
+++ b/libjava/classpath/javax/swing/undo/CannotUndoException.java
@@ -0,0 +1,58 @@
+/* CannotUndoException.java
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.undo;
+
+
+/**
+ * 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
+{
+ /**
+ * Constructs a new instance of a <code>CannotUndoException</code>.
+ */
+ public CannotUndoException()
+ {
+ super();
+ }
+}
diff --git a/libjava/classpath/javax/swing/undo/CompoundEdit.java b/libjava/classpath/javax/swing/undo/CompoundEdit.java
new file mode 100644
index 000000000..64e51740d
--- /dev/null
+++ b/libjava/classpath/javax/swing/undo/CompoundEdit.java
@@ -0,0 +1,400 @@
+/* CompoundEdit.java -- Combines multiple UndoableEdits.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.undo;
+
+import java.util.Vector;
+
+/**
+ * An editing action that consists of multiple
+ * <code>UndoableEdits</code>.
+ *
+ * <p>The use of a <code>CompoundEdit</code> is divided in two separate
+ * phases.</p>
+ *
+ * <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
+{
+ /**
+ * The identifier of this class in object serialization. Determined
+ * using the serialver tool of Sun J2SE 1.4.1_01.
+ */
+ private static final long serialVersionUID = -6512679249930119683L;
+
+
+ /**
+ * The <code>UndoableEdit</code>s being combined into a compound
+ * editing action.
+ */
+ protected Vector<UndoableEdit> edits;
+
+
+ /**
+ * Indicates whether the creation of this CompoundEdit is still in
+ * progress. Initially, the value of this flag is
+ * <code>true</code>. The {@link #end()} method changes the flag to
+ * <code>false</code>.
+ */
+ private boolean inProgress;
+
+
+ /**
+ * Constructs a new CompoundEdit.
+ */
+ public CompoundEdit()
+ {
+ edits = new Vector<UndoableEdit>();
+ inProgress = true;
+ }
+
+
+ /**
+ * Undoes all edits that are part of of this
+ * <code>CompoundEdit</code>. The compound elements will receive the
+ * <code>undo</code> message in the reverse order of addition.
+ *
+ * @throws CannotUndoException if {@link #canUndo()} returns
+ * <code>false</code>. This can happen if {@link #end()} has not
+ * been called on this <code>CompoundEdit</code>, or if this edit
+ * has already been undone.
+ *
+ * @see #canUndo()
+ * @see #redo()
+ */
+ public void undo()
+ throws CannotUndoException
+ {
+ // AbstractUndoableEdit.undo() will throw a CannotUndoException if
+ // canUndo returns false.
+ super.undo();
+
+ for (int i = edits.size() - 1; i >= 0; i--)
+ edits.elementAt(i).undo();
+ }
+
+
+ /**
+ * Redoes all edits that are part of of this
+ * <code>CompoundEdit</code>. The compound elements will receive the
+ * <code>undo</code> message in the same order as they were added.
+ *
+ * @throws CannotRedoException if {@link #canRedo()} returns
+ * <code>false</code>. This can happen if {@link #end()} has not
+ * been called on this <code>CompoundEdit</code>, or if this edit
+ * has already been redone.
+ *
+ * @see #canRedo()
+ * @see #undo()
+ */
+ public void redo()
+ throws CannotRedoException
+ {
+ // AbstractUndoableEdit.redo() will throw a CannotRedoException if
+ // canRedo returns false.
+ super.redo();
+
+ for (int i = 0; i < edits.size(); i++)
+ edits.elementAt(i).redo();
+ }
+
+
+ /**
+ * Returns the the <code>UndoableEdit</code> that was last added to
+ * this compound.
+ */
+ protected UndoableEdit lastEdit()
+ {
+ if (edits.size() == 0)
+ return null;
+ else
+ return edits.elementAt(edits.size() - 1);
+ }
+
+
+ /**
+ * Informs this edit action, and all compound edits, that they will
+ * no longer be used. Some actions might use this information to
+ * release resources such as open files. Called by {@link
+ * UndoManager} before this action is removed from the edit queue.
+ *
+ * <p>The compound elements will receive the
+ * <code>die</code> message in the reverse order of addition.
+ */
+ public void die()
+ {
+ for (int i = edits.size() - 1; i >= 0; i--)
+ 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 (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;
+ }
+}
diff --git a/libjava/classpath/javax/swing/undo/StateEdit.java b/libjava/classpath/javax/swing/undo/StateEdit.java
new file mode 100644
index 000000000..819d052c5
--- /dev/null
+++ b/libjava/classpath/javax/swing/undo/StateEdit.java
@@ -0,0 +1,265 @@
+/* StateEdit.java -- UndoableEdit for StateEditable implementations.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.undo;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+
+/**
+ * A helper class, making it easy to support undo and redo.
+ *
+ * <p>The following example shows how to use this class.</p>
+ *
+ * <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>
+ *
+ * <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
+{
+ /**
+ * 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 and match its value. The value used here has
+ * been in every JDK release at least from 1.2 to 1.5.
+ */
+ protected static final String RCSID = "$" +
+ "Id: StateEdit.java,v 1.6 1997/10/01 20:05:51 sandipc Exp $";
+
+
+ /**
+ * The object which is being edited by this <code>StateEdit</code>.
+ */
+ protected StateEditable object;
+
+
+ /**
+ * The state of <code>object</code> at the time of constructing
+ * this <code>StateEdit</code>.
+ */
+ protected Hashtable<Object, Object> preState;
+
+
+ /**
+ * The state of <code>object</code> at the time when {@link #end()}
+ * was called.
+ */
+ protected Hashtable<Object, Object> postState;
+
+
+ /**
+ * A human-readable name for this edit action.
+ */
+ protected String undoRedoName;
+
+
+ /**
+ * Constructs a <code>StateEdit</code>, specifying the object whose
+ * state is being edited.
+ *
+ * @param obj the object whose state is being edited by this
+ * <code>StateEdit</code>.
+ */
+ public StateEdit(StateEditable obj)
+ {
+ init(obj, null);
+ }
+
+
+ /**
+ * Constructs a <code>StateEdit</code>, specifying the object whose
+ * state is being edited.
+ *
+ * @param obj the object whose state is being edited by this
+ * <code>StateEdit</code>.
+ *
+ * @param name the human-readable name of the editing action.
+ */
+ public StateEdit(StateEditable obj, String name)
+ {
+ init(obj, name);
+ }
+
+
+ /**
+ * Initializes this <code>StateEdit</code>. The edited object will
+ * be asked to store its current state into {@link #preState}.
+ *
+ * @param obj the object being edited.
+ *
+ * @param name the human-readable name of the editing action.
+ */
+ protected void init(StateEditable obj, String name)
+ {
+ object = obj;
+ undoRedoName = name;
+ preState = new Hashtable<Object,Object>();
+ postState = new Hashtable<Object,Object>();
+ obj.storeState(preState);
+ }
+
+
+ /**
+ * Informs this <code>StateEdit</code> that all edits are finished.
+ * The edited object will be asked to store its state into {@link
+ * #postState}, and any redundant entries will get removed from
+ * {@link #preState} and {@link #postState}.
+ */
+ public void end()
+ {
+ object.storeState(postState);
+ removeRedundantState();
+ }
+
+
+ /**
+ * Undoes this edit operation. The edited object will be asked to
+ * {@linkplain StateEditable#restoreState restore its state} from
+ * {@link #preState}.
+ *
+ * @throws CannotUndoException if {@link #canUndo()} returns
+ * <code>false</code>, for example because this action has already
+ * been undone.
+ */
+ public void undo()
+ {
+ super.undo();
+ object.restoreState(preState);
+ }
+
+
+ /**
+ * Redoes this edit operation. The edited object will be asked to
+ * {@linkplain StateEditable#restoreState restore its state} from
+ * {@link #postState}.
+ *
+ * @throws CannotRedoException if {@link #canRedo()} returns
+ * <code>false</code>, for example because this action has not yet
+ * been undone.
+ */
+ public void redo()
+ {
+ super.redo();
+ object.restoreState(postState);
+ }
+
+
+ /**
+ * Returns a human-readable, localized name that describes this
+ * editing action and can be displayed to the user.
+ *
+ * @return the name, or <code>null</code> if no presentation
+ * name is available.
+ */
+ public String getPresentationName()
+ {
+ return undoRedoName;
+ }
+
+
+ /**
+ * 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()
+ {
+ Iterator<Object> i = preState.keySet().iterator();
+ while (i.hasNext())
+ {
+ Object key = i.next();
+ if (postState.containsKey(key))
+ {
+ if (preState.get(key).equals(postState.get(key)))
+ {
+ i.remove();
+ postState.remove(key);
+ }
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/javax/swing/undo/StateEditable.java b/libjava/classpath/javax/swing/undo/StateEditable.java
new file mode 100644
index 000000000..7e6cc9785
--- /dev/null
+++ b/libjava/classpath/javax/swing/undo/StateEditable.java
@@ -0,0 +1,114 @@
+/* StateEditable.java -- Interface for collaborating with StateEdit.
+ Copyright (C) 2002, 2003, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.undo;
+
+import java.util.Hashtable;
+
+
+/**
+ * The interface for objects whose state can be undone or redone by a
+ * {@link StateEdit} action.
+ *
+ * <p>The following example shows how to write a class that implements
+ * this interface.
+ *
+ * <pre> class Foo
+ * implements StateEditable
+ * {
+ * private String name;
+ *
+ * public void setName(String n) { name = n; }
+ *
+ * public void restoreState(Hashtable h)
+ * {
+ * if (h.containsKey("name"))
+ * setName((String) h.get("name"));
+ * }
+ *
+ * public void storeState(Hashtable s)
+ * {
+ * s.put("name", name);
+ * }
+ * }</pre>
+ *
+ * @see StateEdit
+ *
+ * @author Andrew Selkirk (aselkirk@sympatico.ca)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public interface StateEditable
+{
+ /**
+ * 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 and match its value. The value used here has
+ * been in every JDK release at least from 1.2 to 1.5.
+ */
+ String RCSID = "$" +
+ "Id: StateEditable.java,v 1.2 1997/09/08 19:39:08 marklin Exp $";
+
+
+ /**
+ * 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 {@link
+ * 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);
+
+
+ /**
+ * Stores any editable state information into the specified hash
+ * table.
+ *
+ * @param state a hash table for storing relevant state
+ * information.
+ */
+ void storeState(Hashtable<Object, Object> state);
+}
diff --git a/libjava/classpath/javax/swing/undo/UndoManager.java b/libjava/classpath/javax/swing/undo/UndoManager.java
new file mode 100644
index 000000000..9b10cc575
--- /dev/null
+++ b/libjava/classpath/javax/swing/undo/UndoManager.java
@@ -0,0 +1,625 @@
+/* UndoManager.java --
+ Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.undo;
+
+import javax.swing.UIManager;
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.event.UndoableEditListener;
+
+
+/**
+ * A manager for providing an application&#x2019;s undo/redo
+ * functionality.
+ *
+ * <p>Tyipcally, an application will create only one single instance
+ * of UndoManager. When the user performs an undoable action, for
+ * instance changing the color of an object from green to blue, the
+ * application registers an {@link UndoableEdit} object with the
+ * <code>UndoManager</code>. To implement the &#x201c;undo&#x201d; and
+ * &#x201c;redo&#x201d; menu commands, the application invokes the
+ * UndoManager&#x2019;s {@link #undo} and {@link #redo} methods. The
+ * human-readable text of these menu commands is provided by {@link
+ * #getUndoPresentationName} and {@link #getRedoPresentationName},
+ * respectively. To determine whether the menu item should be
+ * selectable or greyed out, use {@link #canUndo} and {@link
+ * #canRedo}.
+ *
+ * <p>The UndoManager will only keep a specified number of editing
+ * actions, the <em>limit</em>. The value of this parameter can be
+ * retrieved by calling {@link #getLimit} and set with {@link
+ * #setLimit}. If more UndoableEdits are added to the UndoManager,
+ * the oldest actions will be discarded.
+ *
+ * <p>Some applications do not provide separate menu commands for
+ * &#x201c;undo&#x201d; and &#x201c;redo.&#x201d; Instead, they
+ * have just a single command whose text switches between the two.
+ * Such applications would use an UndoManager with a <code>limit</code>
+ * of 1. The text of this combined menu item is available via
+ * {@link #getUndoOrRedoPresentationName}, and it is implemented
+ * by calling {@link #undoOrRedo}.
+ *
+ * <p><b>Thread Safety:</b> In constrast to the other classes of the
+ * <code>javax.swing.undo</code> package, the public methods of an
+ * <code>UndoManager</code> are safe to call from concurrent threads.
+ * The caller does not need to perform external synchronization, and
+ * {@link javax.swing.event.UndoableEditEvent} sources do not need to
+ * broadcast their events from inside the Swing worker thread.
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class UndoManager
+ extends CompoundEdit
+ implements UndoableEditListener
+{
+ /**
+ * The unique ID for serializing instances of this class. Determined
+ * using the <code>serialver</code> tool of Sun JDK 1.4.1_01 on
+ * GNU/Linux.
+ */
+ static final long serialVersionUID = -2077529998244066750L;
+
+
+ /**
+ * An index into the inherited {@link #edits} Vector that indicates
+ * at which position newly added editing actions would get inserted.
+ *
+ * <p>Normally, the value of <code>indexOfNextAdd</code> equals
+ * the number of UndoableEdits stored by this UndoManager, i.e.
+ * <code>edits.size()</code>. For each call to {@link #undo},
+ * <code>indexOfNextAdd</code> is decremented by one. For each
+ * call to {@link #redo}, it is incremented again.
+ */
+ int indexOfNextAdd;
+
+
+ /**
+ * The maximum number of UndoableEdits stored by this UndoManager.
+ */
+ int limit;
+
+
+ /**
+ * Constructs an UndoManager.
+ *
+ * <p>The <code>limit</code> of the freshly constructed UndoManager
+ * is 100.
+ */
+ public UndoManager()
+ {
+ limit = 100;
+ }
+
+
+ /**
+ * Returns a string representation for this UndoManager. This may be
+ * useful for debugging purposes. For the text of menu items, please
+ * refer to {@link #getUndoPresentationName}, {@link
+ * #getRedoPresentationName}, and {@link
+ * #getUndoOrRedoPresentationName}.
+ */
+ public String toString()
+ {
+ return super.toString()
+ + " limit: " + limit
+ + " indexOfNextAdd: " + indexOfNextAdd;
+ }
+
+
+ /**
+ * Puts this UndoManager into a state where it acts as a normal
+ * {@link CompoundEdit}. It is unlikely that an application would
+ * want to do this.
+ */
+ public synchronized void end()
+ {
+ super.end();
+ trimEdits(indexOfNextAdd, edits.size() - 1);
+ }
+
+
+ /**
+ * Returns how many edits this UndoManager can maximally hold.
+ *
+ * @see #setLimit
+ */
+ public synchronized int getLimit()
+ {
+ return limit;
+ }
+
+
+ /**
+ * Changes the maximal number of edits that this UndoManager can
+ * process. If there are currently more edits than the new limit
+ * allows, they will receive a {@link UndoableEdit#die() die}
+ * message in reverse order of addition.
+ *
+ * @param limit the new limit.
+ *
+ * @throws IllegalStateException if {@link #end()} has already been
+ * called on this UndoManager.
+ */
+ public synchronized void setLimit(int limit)
+ {
+ if (!isInProgress())
+ throw new IllegalStateException();
+
+ this.limit = limit;
+ trimForLimit();
+ }
+
+
+ /**
+ * Discards all editing actions that are currently registered with
+ * this UndoManager. Each {@link UndoableEdit} will receive a {@link
+ * UndoableEdit#die() die message}.
+ */
+ public synchronized void discardAllEdits()
+ {
+ int size;
+
+ size = edits.size();
+ for (int i = size - 1; i >= 0; i--)
+ edits.get(i).die();
+ indexOfNextAdd = 0;
+ edits.clear();
+ }
+
+
+ /**
+ * Called by various internal methods in order to enforce
+ * the <code>limit</code> value.
+ */
+ protected void trimForLimit()
+ {
+ int high, s;
+
+ s = edits.size();
+
+ /* The Sun J2SE1.4.1_01 implementation can be observed to do
+ * nothing (instead of throwing an exception) with a negative or
+ * zero limit. It may be debatable whether this is the best
+ * behavior, but we replicate it for sake of compatibility.
+ */
+ if (limit <= 0 || s <= limit)
+ return;
+
+ high = Math.min(indexOfNextAdd + limit/2 - 1, s - 1);
+ trimEdits(high + 1, s - 1);
+ trimEdits(0, high - limit);
+ }
+
+
+ /**
+ * Discards a range of edits. All edits in the range <code>[from
+ * .. to]</code> will receive a {@linkplain UndoableEdit#die() die
+ * message} before being removed from the edits array. If
+ * <code>from</code> is greater than <code>to</code>, nothing
+ * happens.
+ *
+ * @param from the lower bound of the range of edits to be
+ * discarded.
+ *
+ * @param to the upper bound of the range of edits to be discarded.
+ */
+ protected void trimEdits(int from, int to)
+ {
+ if (from > to)
+ return;
+
+ for (int i = to; i >= from; i--)
+ edits.get(i).die();
+
+ // Remove the range [from .. to] from edits. If from == to, which
+ // is likely to be a very common case, we can do better than
+ // creating a sub-list and clearing it.
+ if (to == from)
+ edits.remove(from);
+ else
+ edits.subList(from, to + 1).clear();
+
+ if (indexOfNextAdd > to)
+ indexOfNextAdd = indexOfNextAdd - to + from - 1;
+ else if (indexOfNextAdd >= from)
+ indexOfNextAdd = from;
+ }
+
+
+ /**
+ * Determines which significant edit would be undone if {@link
+ * #undo()} was called.
+ *
+ * @return the significant edit that would be undone, or
+ * <code>null</code> if no significant edit would be affected by
+ * calling {@link #undo()}.
+ */
+ protected UndoableEdit editToBeUndone()
+ {
+ UndoableEdit result;
+
+ for (int i = indexOfNextAdd - 1; i >= 0; i--)
+ {
+ result = edits.get(i);
+ if (result.isSignificant())
+ return result;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Determines which significant edit would be redone if {@link
+ * #redo()} was called.
+ *
+ * @return the significant edit that would be redone, or
+ * <code>null</code> if no significant edit would be affected by
+ * calling {@link #redo()}.
+ */
+ protected UndoableEdit editToBeRedone()
+ {
+ UndoableEdit result;
+
+ for (int i = indexOfNextAdd; i < edits.size(); i++)
+ {
+ result = edits.get(i);
+ if (result.isSignificant())
+ return result;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Undoes all editing actions in reverse order of addition,
+ * up to the specified action,
+ *
+ * @param edit the last editing action to be undone.
+ */
+ protected void undoTo(UndoableEdit edit)
+ throws CannotUndoException
+ {
+ UndoableEdit cur;
+
+ if (!edits.contains(edit))
+ throw new CannotUndoException();
+
+ while (true)
+ {
+ indexOfNextAdd -= 1;
+ cur = edits.get(indexOfNextAdd);
+ cur.undo();
+ if (cur == edit)
+ return;
+ }
+ }
+
+
+ /**
+ * Redoes all editing actions in the same order as they were
+ * added to this UndoManager, up to the specified action.
+ *
+ * @param edit the last editing action to be redone.
+ */
+ protected void redoTo(UndoableEdit edit)
+ throws CannotRedoException
+ {
+ UndoableEdit cur;
+
+ if (!edits.contains(edit))
+ throw new CannotRedoException();
+
+ while (true)
+ {
+ cur = edits.get(indexOfNextAdd);
+ indexOfNextAdd += 1;
+ cur.redo();
+ if (cur == edit)
+ return;
+ }
+ }
+
+
+ /**
+ * Undoes or redoes the last action. If the last action has already
+ * been undone, it will be re-done, and vice versa.
+ *
+ * <p>This is useful for applications that do not present a separate
+ * undo and redo facility, but just have a single menu item for
+ * undoing and redoing the very last action. Such applications will
+ * use an <code>UndoManager</code> whose <code>limit</code> is 1.
+ */
+ public synchronized void undoOrRedo()
+ throws CannotRedoException, CannotUndoException
+ {
+ if (indexOfNextAdd == edits.size())
+ undo();
+ else
+ redo();
+ }
+
+
+ /**
+ * Determines whether it would be possible to either undo or redo
+ * this editing action.
+ *
+ * <p>This is useful for applications that do not present a separate
+ * undo and redo facility, but just have a single menu item for
+ * undoing and redoing the very last action. Such applications will
+ * use an <code>UndoManager</code> whose <code>limit</code> is 1.
+ *
+ * @return <code>true</code> to indicate that this action can be
+ * undone or redone; <code>false</code> if neither is possible at
+ * the current time.
+ */
+ public synchronized boolean canUndoOrRedo()
+ {
+ return indexOfNextAdd == edits.size() ? canUndo() : canRedo();
+ }
+
+
+ /**
+ * Undoes one significant edit action. If insignificant actions have
+ * been posted after the last signficant action, the insignificant
+ * ones will be undone first.
+ *
+ * <p>However, if {@link #end()} has been called on this
+ * UndoManager, it will behave like a normal {@link
+ * CompoundEdit}. In this case, all actions will be undone in
+ * reverse order of addition. Typical applications will never call
+ * {@link #end()} on their <code>UndoManager</code>.
+ *
+ * @throws CannotUndoException if no action can be undone.
+ *
+ * @see #canUndo()
+ * @see #redo()
+ * @see #undoOrRedo()
+ */
+ public synchronized void undo()
+ throws CannotUndoException
+ {
+ if (!isInProgress())
+ {
+ super.undo();
+ return;
+ }
+
+ UndoableEdit edit = editToBeUndone();
+ if (edit == null)
+ throw new CannotUndoException();
+
+ undoTo(edit);
+ }
+
+
+ /**
+ * Determines whether it would be possible to undo this editing
+ * action.
+ *
+ * @return <code>true</code> to indicate that this action can be
+ * undone; <code>false</code> otherwise.
+ *
+ * @see #undo()
+ * @see #canRedo()
+ * @see #canUndoOrRedo()
+ */
+ public synchronized boolean canUndo()
+ {
+ UndoableEdit edit;
+
+ if (!isInProgress())
+ return super.canUndo();
+
+ edit = editToBeUndone();
+ return edit != null && edit.canUndo();
+ }
+
+
+
+ /**
+ * Redoes one significant edit action. If insignificant actions have
+ * been posted in between, the insignificant ones will be redone
+ * first.
+ *
+ * <p>However, if {@link #end()} has been called on this
+ * UndoManager, it will behave like a normal {@link
+ * CompoundEdit}. In this case, <em>all</em> actions will be redone
+ * in order of addition. Typical applications will never call {@link
+ * #end()} on their <code>UndoManager</code>.
+ *
+ * @throws CannotRedoException if no action can be redone.
+ *
+ * @see #canRedo()
+ * @see #redo()
+ * @see #undoOrRedo()
+ */
+ public synchronized void redo()
+ throws CannotRedoException
+ {
+ if (!isInProgress())
+ {
+ super.redo();
+ return;
+ }
+
+ UndoableEdit edit = editToBeRedone();
+ if (edit == null)
+ throw new CannotRedoException();
+
+ redoTo(edit);
+ }
+
+
+ /**
+ * 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()
+ * @see #canUndoOrRedo()
+ */
+ public synchronized boolean canRedo()
+ {
+ UndoableEdit edit;
+
+ if (!isInProgress())
+ return super.canRedo();
+
+ edit = editToBeRedone();
+ return edit != null && edit.canRedo();
+ }
+
+
+ /**
+ * Registers an undoable editing action with this UndoManager. If
+ * the capacity <code>limit</code> is reached, the oldest action
+ * will be discarded (and receives a {@linkplain UndoableEdit#die()
+ * die message}. Equally, any actions that were undone (but not re-done)
+ * will be discarded, too.
+ *
+ * @param edit the editing action that is added to this UndoManager.
+ *
+ * @return <code>true</code> if <code>edit</code> could be
+ * incorporated; <code>false</code> if <code>edit</code> has not
+ * been incorporated because {@link #end()} has already been called
+ * on this <code>UndoManager</code>.
+ */
+ public synchronized boolean addEdit(UndoableEdit edit)
+ {
+ boolean result;
+
+ // Discard any edits starting at indexOfNextAdd.
+ trimEdits(indexOfNextAdd, edits.size() - 1);
+
+ result = super.addEdit(edit);
+ indexOfNextAdd = edits.size();
+ trimForLimit();
+ return result;
+ }
+
+
+ /**
+ * Calculates a localized text for presenting the undo or redo
+ * action to the user, for example in the form of a menu command.
+ *
+ * <p>This is useful for applications that do not present a separate
+ * undo and redo facility, but just have a single menu item for
+ * undoing and redoing the very last action. Such applications will
+ * use an <code>UndoManager</code> whose <code>limit</code> is 1.
+ *
+ * @return the redo presentation name if the last action has already
+ * been undone, or the undo presentation name otherwise.
+ *
+ * @see #getUndoPresentationName()
+ * @see #getRedoPresentationName()
+ */
+ public synchronized String getUndoOrRedoPresentationName()
+ {
+ if (indexOfNextAdd == edits.size())
+ return getUndoPresentationName();
+ else
+ return getRedoPresentationName();
+ }
+
+
+ /**
+ * Calculates a localized text for presenting the undo action
+ * to the user, for example in the form of a menu command.
+ */
+ public synchronized String getUndoPresentationName()
+ {
+ UndoableEdit edit;
+
+ if (!isInProgress())
+ return super.getUndoPresentationName();
+
+ edit = editToBeUndone();
+ if (edit == null)
+ return UIManager.getString("AbstractUndoableEdit.undoText");
+ else
+ return edit.getUndoPresentationName();
+ }
+
+
+ /**
+ * Calculates a localized text for presenting the redo action
+ * to the user, for example in the form of a menu command.
+ */
+ public synchronized String getRedoPresentationName()
+ {
+ UndoableEdit edit;
+
+ if (!isInProgress())
+ return super.getRedoPresentationName();
+
+ edit = editToBeRedone();
+ if (edit == null)
+ return UIManager.getString("AbstractUndoableEdit.redoText");
+ else
+ return edit.getRedoPresentationName();
+ }
+
+
+ /**
+ * Registers the edit action of an {@link UndoableEditEvent}
+ * with this UndoManager.
+ *
+ * <p><b>Thread Safety:</b> This method may safely be invoked from
+ * concurrent threads. The caller does not need to perform external
+ * synchronization. This means that {@link
+ * javax.swing.event.UndoableEditEvent} sources do not need to broadcast
+ * their events from inside the Swing worker thread.
+ *
+ * @param event the event whose <code>edit</code> will be
+ * passed to {@link #addEdit}.
+ *
+ * @see UndoableEditEvent#getEdit()
+ * @see #addEdit
+ */
+ public void undoableEditHappened(UndoableEditEvent event)
+ {
+ // Note that this method does not need to be synchronized,
+ // because addEdit will obtain and release the mutex.
+ addEdit(event.getEdit());
+ }
+}
diff --git a/libjava/classpath/javax/swing/undo/UndoableEdit.java b/libjava/classpath/javax/swing/undo/UndoableEdit.java
new file mode 100644
index 000000000..1a08ecaa5
--- /dev/null
+++ b/libjava/classpath/javax/swing/undo/UndoableEdit.java
@@ -0,0 +1,157 @@
+/* UndoableEdit.java --
+ Copyright (C) 2002, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.undo;
+
+/**
+ * An editing operation that supports undo/redoability.
+ *
+ * @author Andrew Selkirk
+ */
+public interface UndoableEdit
+{
+
+ /**
+ * Incorporates another editing action into this one, thus forming a
+ * combined action.
+ *
+ * @param edit the editing action to be incorporated.
+ *
+ * @return <code>true</code> if the edit was combined successfully, and
+ * <code>false</code> if it could not be combined.
+ */
+ boolean addEdit(UndoableEdit edit);
+
+ /**
+ * 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()
+ */
+ boolean canRedo();
+
+ /**
+ * Determines whether it would be possible to undo this editing
+ * action.
+ *
+ * @return <code>true</code> to indicate that this action can be
+ * undone, <code>false</code> otherwise.
+ *
+ * @see #undo()
+ * @see #canRedo()
+ */
+ boolean canUndo();
+
+ /**
+ * 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.
+ */
+ void die();
+
+ /**
+ * Returns a human-readable, localized name that describes this
+ * editing action and can be displayed to the user.
+ *
+ * @return The presentation name.
+ */
+ String getPresentationName();
+
+ /**
+ * Returns the redo presentation name.
+ *
+ * @return The redo presentation name.
+ */
+ String getRedoPresentationName();
+
+ /**
+ * Returns the undo presentation name.
+ *
+ * @return The undo presentation name.
+ */
+ String getUndoPresentationName();
+
+ /**
+ * 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.
+ *
+ * @return <code>true</code> to indicate that the action is
+ * significant enough for being separately undoable, or
+ * <code>false</code> otherwise.
+ */
+ boolean isSignificant();
+
+ /**
+ * Redoes this editing action.
+ *
+ * @throws CannotRedoException if the edit cannot be undone.
+ *
+ * @see #canRedo()
+ * @see #undo()
+ */
+ void redo() throws CannotRedoException;
+
+ /**
+ * Incorporates another editing action into this one, thus forming a
+ * combined action that replaces the argument action.
+ *
+ * @param edit the editing action to be replaced.
+ *
+ * @return <code>true</code> if the edit is successfully replaced, and
+ * <code>false</code> otherwise.
+ */
+ boolean replaceEdit(UndoableEdit edit);
+
+ /**
+ * Undoes this editing action.
+ *
+ * @throws CannotUndoException if the edit cannot be undone.
+ *
+ * @see #canUndo()
+ * @see #redo()
+ */
+ void undo() throws CannotUndoException;
+
+}
diff --git a/libjava/classpath/javax/swing/undo/UndoableEditSupport.java b/libjava/classpath/javax/swing/undo/UndoableEditSupport.java
new file mode 100644
index 000000000..2e5d90954
--- /dev/null
+++ b/libjava/classpath/javax/swing/undo/UndoableEditSupport.java
@@ -0,0 +1,272 @@
+/* UndoableEditSupport.java --
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.undo;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.event.UndoableEditListener;
+
+/**
+ * A helper class for supporting {@link
+ * javax.swing.event.UndoableEditListener}.
+ *
+ * @author Andrew Selkirk (aselkirk@sympatico.ca)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class UndoableEditSupport
+{
+ /**
+ * The number of times that {@link #beginUpdate()} has been called
+ * without a matching call to {@link #endUpdate()}.
+ */
+ protected int updateLevel;
+
+
+ /**
+ * compoundEdit
+ */
+ protected CompoundEdit compoundEdit;
+
+
+ /**
+ * The currently registered listeners.
+ */
+ protected Vector<UndoableEditListener> listeners =
+ new Vector<UndoableEditListener>();
+
+
+ /**
+ * The source of the broadcast UndoableEditEvents.
+ */
+ protected Object realSource;
+
+
+ /**
+ * Constructs a new helper for broadcasting UndoableEditEvents. The
+ * events will indicate the newly constructed
+ * <code>UndoableEditSupport</code> instance as their source.
+ *
+ * @see #UndoableEditSupport(java.lang.Object)
+ */
+ public UndoableEditSupport()
+ {
+ realSource = this;
+ }
+
+
+ /**
+ * Constructs a new helper for broadcasting UndoableEditEvents.
+ *
+ * @param realSource the source of the UndoableEditEvents that will
+ * be broadcast by this helper. If <code>realSource</code> is
+ * <code>null</code>, the events will indicate the newly constructed
+ * <code>UndoableEditSupport</code> instance as their source.
+ */
+ public UndoableEditSupport(Object realSource)
+ {
+ if (realSource == null)
+ realSource = this;
+ this.realSource = realSource;
+ }
+
+
+ /**
+ * Returns a string representation of this object that may be useful
+ * for debugging.
+ */
+ public String toString()
+ {
+ // Note that often, this.realSource == this. Therefore, dumping
+ // realSource without additional checks may lead to infinite
+ // recursion. See Classpath bug #7119.
+ return super.toString() + " updateLevel: " + updateLevel
+ + " listeners: " + listeners + " compoundEdit: " + compoundEdit;
+ }
+
+
+ /**
+ * Registers a listener.
+ *
+ * @param val the listener to be added.
+ */
+ public synchronized void addUndoableEditListener(UndoableEditListener val)
+ {
+ listeners.add(val);
+ }
+
+
+ /**
+ * Unregisters a listener.
+ * @param val the listener to be removed.
+ */
+ public synchronized void removeUndoableEditListener(UndoableEditListener val)
+ {
+ listeners.removeElement(val);
+ }
+
+
+ /**
+ * Returns an array containing the currently registered listeners.
+ */
+ public synchronized UndoableEditListener[] getUndoableEditListeners()
+ {
+ UndoableEditListener[] result = new UndoableEditListener[listeners.size()];
+ return listeners.toArray(result);
+ }
+
+
+ /**
+ * Notifies all registered listeners that an {@link
+ * UndoableEditEvent} has occured.
+ *
+ * <p><b>Lack of Thread Safety:</b> It is <em>not</em> safe to call
+ * this method from concurrent threads, unless the call is protected
+ * by a synchronization on this <code>UndoableEditSupport</code>
+ * instance.
+ *
+ * @param edit the edit action to be posted.
+ */
+ protected void _postEdit(UndoableEdit edit)
+ {
+ UndoableEditEvent event;
+ Iterator<UndoableEditListener> iter;
+
+ // Do nothing if we have no listeners.
+ if (listeners.isEmpty())
+ return;
+
+ event = new UndoableEditEvent(realSource, edit);
+
+ // We clone the vector because this allows listeners to register
+ // or unregister listeners in their undoableEditHappened method.
+ // Otherwise, this would throw exceptions (in the case of
+ // Iterator, a java.util.ConcurrentModificationException; in the
+ // case of a direct loop over the Vector elements, some
+ // index-out-of-bounds exception).
+ iter = new Vector<UndoableEditListener>(listeners).iterator();
+ while (iter.hasNext())
+ iter.next().undoableEditHappened(event);
+ }
+
+
+ /**
+ * If {@link #beginUpdate} has been called (so that the current
+ * update level is greater than zero), adds the specified edit
+ * to {@link #compoundEdit}. Otherwise, notify listeners of the
+ * edit by calling {@link #_postEdit(UndoableEdit)}.
+ *
+ * <p><b>Thread Safety:</b> It is safe to call this method from any
+ * thread without external synchronization.
+ *
+ * @param edit the edit action to be posted.
+ */
+ public synchronized void postEdit(UndoableEdit edit)
+ {
+ if (compoundEdit != null)
+ compoundEdit.addEdit(edit);
+ else
+ _postEdit(edit);
+ }
+
+
+ /**
+ * Returns the current update level.
+ */
+ public int getUpdateLevel()
+ {
+ return updateLevel;
+ }
+
+
+ /**
+ * Starts a (possibly nested) update session. If the current update
+ * level is zero, {@link #compoundEdit} is set to the result of the
+ * {@link #createCompoundEdit} method. In any case, the update level
+ * is increased by one.
+ *
+ * <p><b>Thread Safety:</b> It is safe to call this method from any
+ * thread without external synchronization.
+ */
+ public synchronized void beginUpdate()
+ {
+ if (compoundEdit == null)
+ compoundEdit = createCompoundEdit();
+ ++updateLevel;
+ }
+
+
+ /**
+ * Creates a new instance of {@link CompoundEdit}. Called by {@link
+ * #beginUpdate}. If a subclass wants {@link #beginUpdate} to work
+ * on a specific {@link #compoundEdit}, it should override this
+ * method.
+ *
+ * @return a newly created instance of {@link CompoundEdit}.
+ */
+ protected CompoundEdit createCompoundEdit()
+ {
+ return new CompoundEdit();
+ }
+
+
+ /**
+ * Ends an update session. If the terminated session was the
+ * outermost session, {@link #compoundEdit} will receive an
+ * <code>end</code> message, and {@link #_postEdit} gets called in
+ * order to notify any listeners. Finally, the
+ * <code>compoundEdit</code> is discarded.
+ *
+ * <p><b>Thread Safety:</b> It is safe to call this method from any
+ * thread without external synchronization.
+ */
+ public synchronized void endUpdate()
+ {
+ if (updateLevel == 0)
+ throw new IllegalStateException();
+
+ if (--updateLevel > 0)
+ return;
+
+ compoundEdit.end();
+ _postEdit(compoundEdit);
+ compoundEdit = null;
+ }
+}
diff --git a/libjava/classpath/javax/swing/undo/package.html b/libjava/classpath/javax/swing/undo/package.html
new file mode 100644
index 000000000..125bd4446
--- /dev/null
+++ b/libjava/classpath/javax/swing/undo/package.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in javax.swing.undo package.
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - javax.swing.undo</title></head>
+
+<body>
+<p>Provides a mechanism to support undo/redo operations.</p>
+
+</body>
+</html>