feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,278 @@
/*
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing.undo;
import java.io.Serializable;
import javax.swing.UIManager;
/**
* An abstract implementation of <code>UndoableEdit</code>,
* implementing simple responses to all boolean methods in
* that interface.
*
* @author Ray Ryan
*/
public class AbstractUndoableEdit implements UndoableEdit, Serializable {
/**
* String returned by <code>getUndoPresentationName</code>;
* as of Java 2 platform v1.3.1 this field is no longer used. This value
* is now localized and comes from the defaults table with key
* <code>AbstractUndoableEdit.undoText</code>.
*
* @see javax.swing.UIDefaults
*/
protected static final String UndoName = "Undo";
/**
* String returned by <code>getRedoPresentationName</code>;
* as of Java 2 platform v1.3.1 this field is no longer used. This value
* is now localized and comes from the defaults table with key
* <code>AbstractUndoableEdit.redoText</code>.
*
* @see javax.swing.UIDefaults
*/
protected static final String RedoName = "Redo";
/**
* Defaults to true; becomes false if this edit is undone, true
* again if it is redone.
*/
boolean hasBeenDone;
/**
* True if this edit has not received <code>die</code>; defaults
* to <code>true</code>.
*/
boolean alive;
/**
* Creates an <code>AbstractUndoableEdit</code> which defaults
* <code>hasBeenDone</code> and <code>alive</code> to <code>true</code>.
*/
public AbstractUndoableEdit() {
super();
hasBeenDone = true;
alive = true;
}
/**
* Sets <code>alive</code> to false. Note that this
* is a one way operation; dead edits cannot be resurrected.
* Sending <code>undo</code> or <code>redo</code> to
* a dead edit results in an exception being thrown.
*
* <p>Typically an edit is killed when it is consolidated by
* another edit's <code>addEdit</code> or <code>replaceEdit</code>
* method, or when it is dequeued from an <code>UndoManager</code>.
*/
public void die() {
alive = false;
}
/**
* Throws <code>CannotUndoException</code> if <code>canUndo</code>
* returns <code>false</code>. Sets <code>hasBeenDone</code>
* to <code>false</code>. Subclasses should override to undo the
* operation represented by this edit. Override should begin with
* a call to super.
*
* @exception CannotUndoException if <code>canUndo</code>
* returns <code>false</code>
* @see #canUndo
*/
public void undo() throws CannotUndoException {
if (!canUndo()) {
throw new CannotUndoException();
}
hasBeenDone = false;
}
/**
* Returns true if this edit is <code>alive</code>
* and <code>hasBeenDone</code> is <code>true</code>.
*
* @return true if this edit is <code>alive</code>
* and <code>hasBeenDone</code> is <code>true</code>
*
* @see #die
* @see #undo
* @see #redo
*/
public boolean canUndo() {
return alive && hasBeenDone;
}
/**
* Throws <code>CannotRedoException</code> if <code>canRedo</code>
* returns false. Sets <code>hasBeenDone</code> to <code>true</code>.
* Subclasses should override to redo the operation represented by
* this edit. Override should begin with a call to super.
*
* @exception CannotRedoException if <code>canRedo</code>
* returns <code>false</code>
* @see #canRedo
*/
public void redo() throws CannotRedoException {
if (!canRedo()) {
throw new CannotRedoException();
}
hasBeenDone = true;
}
/**
* Returns <code>true</code> if this edit is <code>alive</code>
* and <code>hasBeenDone</code> is <code>false</code>.
*
* @return <code>true</code> if this edit is <code>alive</code>
* and <code>hasBeenDone</code> is <code>false</code>
* @see #die
* @see #undo
* @see #redo
*/
public boolean canRedo() {
return alive && !hasBeenDone;
}
/**
* This default implementation returns false.
*
* @param anEdit the edit to be added
* @return false
*
* @see UndoableEdit#addEdit
*/
public boolean addEdit(UndoableEdit anEdit) {
return false;
}
/**
* This default implementation returns false.
*
* @param anEdit the edit to replace
* @return false
*
* @see UndoableEdit#replaceEdit
*/
public boolean replaceEdit(UndoableEdit anEdit) {
return false;
}
/**
* This default implementation returns true.
*
* @return true
* @see UndoableEdit#isSignificant
*/
public boolean isSignificant() {
return true;
}
/**
* This default implementation returns "". Used by
* <code>getUndoPresentationName</code> and
* <code>getRedoPresentationName</code> to
* construct the strings they return. Subclasses should override to
* return an appropriate description of the operation this edit
* represents.
*
* @return the empty string ""
*
* @see #getUndoPresentationName
* @see #getRedoPresentationName
*/
public String getPresentationName() {
return "";
}
/**
* Retreives the value from the defaults table with key
* <code>AbstractUndoableEdit.undoText</code> and returns
* that value followed by a space, followed by
* <code>getPresentationName</code>.
* If <code>getPresentationName</code> returns "",
* then the defaults value is returned alone.
*
* @return the value from the defaults table with key
* <code>AbstractUndoableEdit.undoText</code>, followed
* by a space, followed by <code>getPresentationName</code>
* unless <code>getPresentationName</code> is "" in which
* case, the defaults value is returned alone.
* @see #getPresentationName
*/
public String getUndoPresentationName() {
String name = getPresentationName();
if (!"".equals(name)) {
name = UIManager.getString("AbstractUndoableEdit.undoText") +
" " + name;
} else {
name = UIManager.getString("AbstractUndoableEdit.undoText");
}
return name;
}
/**
* Retreives the value from the defaults table with key
* <code>AbstractUndoableEdit.redoText</code> and returns
* that value followed by a space, followed by
* <code>getPresentationName</code>.
* If <code>getPresentationName</code> returns "",
* then the defaults value is returned alone.
*
* @return the value from the defaults table with key
* <code>AbstractUndoableEdit.redoText</code>, followed
* by a space, followed by <code>getPresentationName</code>
* unless <code>getPresentationName</code> is "" in which
* case, the defaults value is returned alone.
* @see #getPresentationName
*/
public String getRedoPresentationName() {
String name = getPresentationName();
if (!"".equals(name)) {
name = UIManager.getString("AbstractUndoableEdit.redoText") +
" " + name;
} else {
name = UIManager.getString("AbstractUndoableEdit.redoText");
}
return name;
}
/**
* Returns a string that displays and identifies this
* object's properties.
*
* @return a String representation of this object
*/
public String toString()
{
return super.toString()
+ " hasBeenDone: " + hasBeenDone
+ " alive: " + alive;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing.undo;
/**
* Thrown when an UndoableEdit is told to <code>redo()</code> and can't.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Ray Ryan
*/
public class CannotRedoException extends RuntimeException {
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing.undo;
/**
* Thrown when an UndoableEdit is told to <code>undo()</code> and can't.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Ray Ryan
*/
public class CannotUndoException extends RuntimeException {
}

View File

@@ -0,0 +1,262 @@
/*
* Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing.undo;
import java.util.*;
/**
* A concrete subclass of AbstractUndoableEdit, used to assemble little
* UndoableEdits into great big ones.
*
* @author Ray Ryan
*/
public class CompoundEdit extends AbstractUndoableEdit {
/**
* True if this edit has never received <code>end</code>.
*/
boolean inProgress;
/**
* The collection of <code>UndoableEdit</code>s
* undone/redone en masse by this <code>CompoundEdit</code>.
*/
protected Vector<UndoableEdit> edits;
public CompoundEdit() {
super();
inProgress = true;
edits = new Vector<UndoableEdit>();
}
/**
* Sends <code>undo</code> to all contained
* <code>UndoableEdits</code> in the reverse of
* the order in which they were added.
*/
public void undo() throws CannotUndoException {
super.undo();
int i = edits.size();
while (i-- > 0) {
UndoableEdit e = edits.elementAt(i);
e.undo();
}
}
/**
* Sends <code>redo</code> to all contained
* <code>UndoableEdit</code>s in the order in
* which they were added.
*/
public void redo() throws CannotRedoException {
super.redo();
Enumeration cursor = edits.elements();
while (cursor.hasMoreElements()) {
((UndoableEdit)cursor.nextElement()).redo();
}
}
/**
* Returns the last <code>UndoableEdit</code> in
* <code>edits</code>, or <code>null</code>
* if <code>edits</code> is empty.
*/
protected UndoableEdit lastEdit() {
int count = edits.size();
if (count > 0)
return edits.elementAt(count-1);
else
return null;
}
/**
* Sends <code>die</code> to each subedit,
* in the reverse of the order that they were added.
*/
public void die() {
int size = edits.size();
for (int i = size-1; i >= 0; i--)
{
UndoableEdit e = edits.elementAt(i);
// System.out.println("CompoundEdit(" + i + "): Discarding " +
// e.getUndoPresentationName());
e.die();
}
super.die();
}
/**
* If this edit is <code>inProgress</code>,
* accepts <code>anEdit</code> and returns true.
*
* <p>The last edit added to this <code>CompoundEdit</code>
* is given a chance to <code>addEdit(anEdit)</code>.
* If it refuses (returns false), <code>anEdit</code> is
* given a chance to <code>replaceEdit</code> the last edit.
* If <code>anEdit</code> returns false here,
* it is added to <code>edits</code>.
*
* @param anEdit the edit to be added
* @return true if the edit is <code>inProgress</code>;
* otherwise returns false
*/
public boolean addEdit(UndoableEdit anEdit) {
if (!inProgress) {
return false;
} else {
UndoableEdit last = lastEdit();
// If this is the first subedit received, just add it.
// Otherwise, give the last one a chance to absorb the new
// one. If it won't, give the new one a chance to absorb
// the last one.
if (last == null) {
edits.addElement(anEdit);
}
else if (!last.addEdit(anEdit)) {
if (anEdit.replaceEdit(last)) {
edits.removeElementAt(edits.size()-1);
}
edits.addElement(anEdit);
}
return true;
}
}
/**
* Sets <code>inProgress</code> to false.
*
* @see #canUndo
* @see #canRedo
*/
public void end() {
inProgress = false;
}
/**
* Returns false if <code>isInProgress</code> or if super
* returns false.
*
* @see #isInProgress
*/
public boolean canUndo() {
return !isInProgress() && super.canUndo();
}
/**
* Returns false if <code>isInProgress</code> or if super
* returns false.
*
* @see #isInProgress
*/
public boolean canRedo() {
return !isInProgress() && super.canRedo();
}
/**
* Returns true if this edit is in progress--that is, it has not
* received end. This generally means that edits are still being
* added to it.
*
* @see #end
*/
public boolean isInProgress() {
return inProgress;
}
/**
* Returns true if any of the <code>UndoableEdit</code>s
* in <code>edits</code> do.
* Returns false if they all return false.
*/
public boolean isSignificant() {
Enumeration cursor = edits.elements();
while (cursor.hasMoreElements()) {
if (((UndoableEdit)cursor.nextElement()).isSignificant()) {
return true;
}
}
return false;
}
/**
* Returns <code>getPresentationName</code> from the
* last <code>UndoableEdit</code> added to
* <code>edits</code>. If <code>edits</code> is empty,
* calls super.
*/
public String getPresentationName() {
UndoableEdit last = lastEdit();
if (last != null) {
return last.getPresentationName();
} else {
return super.getPresentationName();
}
}
/**
* Returns <code>getUndoPresentationName</code>
* from the last <code>UndoableEdit</code>
* added to <code>edits</code>.
* If <code>edits</code> is empty, calls super.
*/
public String getUndoPresentationName() {
UndoableEdit last = lastEdit();
if (last != null) {
return last.getUndoPresentationName();
} else {
return super.getUndoPresentationName();
}
}
/**
* Returns <code>getRedoPresentationName</code>
* from the last <code>UndoableEdit</code>
* added to <code>edits</code>.
* If <code>edits</code> is empty, calls super.
*/
public String getRedoPresentationName() {
UndoableEdit last = lastEdit();
if (last != null) {
return last.getRedoPresentationName();
} else {
return super.getRedoPresentationName();
}
}
/**
* Returns a string that displays and identifies this
* object's properties.
*
* @return a String representation of this object
*/
public String toString()
{
return super.toString()
+ " inProgress: " + inProgress
+ " edits: " + edits;
}
}

View File

@@ -0,0 +1,193 @@
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing.undo;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
* <P>StateEdit is a general edit for objects that change state.
* Objects being edited must conform to the StateEditable interface.</P>
*
* <P>This edit class works by asking an object to store it's state in
* Hashtables before and after editing occurs. Upon undo or redo the
* object is told to restore it's state from these Hashtables.</P>
*
* A state edit is used as follows:
* <PRE>
* // Create the edit during the "before" state of the object
* StateEdit newEdit = new StateEdit(myObject);
* // Modify the object
* myObject.someStateModifyingMethod();
* // "end" the edit when you are done modifying the object
* newEdit.end();
* </PRE>
*
* <P><EM>Note that when a StateEdit ends, it removes redundant state from
* the Hashtables - A state Hashtable is not guaranteed to contain all
* keys/values placed into it when the state is stored!</EM></P>
*
* @see StateEditable
*
* @author Ray Ryan
*/
public class StateEdit
extends AbstractUndoableEdit {
protected static final String RCSID = "$Id: StateEdit.java,v 1.6 1997/10/01 20:05:51 sandipc Exp $";
//
// Attributes
//
/**
* The object being edited
*/
protected StateEditable object;
/**
* The state information prior to the edit
*/
protected Hashtable<Object,Object> preState;
/**
* The state information after the edit
*/
protected Hashtable<Object,Object> postState;
/**
* The undo/redo presentation name
*/
protected String undoRedoName;
//
// Constructors
//
/**
* Create and return a new StateEdit.
*
* @param anObject The object to watch for changing state
*
* @see StateEdit
*/
public StateEdit(StateEditable anObject) {
super();
init (anObject,null);
}
/**
* Create and return a new StateEdit with a presentation name.
*
* @param anObject The object to watch for changing state
* @param name The presentation name to be used for this edit
*
* @see StateEdit
*/
public StateEdit(StateEditable anObject, String name) {
super();
init (anObject,name);
}
protected void init (StateEditable anObject, String name) {
this.object = anObject;
this.preState = new Hashtable<Object, Object>(11);
this.object.storeState(this.preState);
this.postState = null;
this.undoRedoName = name;
}
//
// Operation
//
/**
* Gets the post-edit state of the StateEditable object and
* ends the edit.
*/
public void end() {
this.postState = new Hashtable<Object, Object>(11);
this.object.storeState(this.postState);
this.removeRedundantState();
}
/**
* Tells the edited object to apply the state prior to the edit
*/
public void undo() {
super.undo();
this.object.restoreState(preState);
}
/**
* Tells the edited object to apply the state after the edit
*/
public void redo() {
super.redo();
this.object.restoreState(postState);
}
/**
* Gets the presentation name for this edit
*/
public String getPresentationName() {
return this.undoRedoName;
}
//
// Internal support
//
/**
* Remove redundant key/values in state hashtables.
*/
protected void removeRedundantState() {
Vector<Object> uselessKeys = new Vector<Object>();
Enumeration myKeys = preState.keys();
// Locate redundant state
while (myKeys.hasMoreElements()) {
Object myKey = myKeys.nextElement();
if (postState.containsKey(myKey) &&
postState.get(myKey).equals(preState.get(myKey))) {
uselessKeys.addElement(myKey);
}
}
// Remove redundant state
for (int i = uselessKeys.size()-1; i >= 0; i--) {
Object myKey = uselessKeys.elementAt(i);
preState.remove(myKey);
postState.remove(myKey);
}
}
} // End of class StateEdit

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing.undo;
import java.util.Hashtable;
/**
* StateEditable defines the interface for objects that can have
* their state undone/redone by a StateEdit.
*
* @see StateEdit
*/
public interface StateEditable {
/** Resource ID for this class. */
public static final String RCSID = "$Id: StateEditable.java,v 1.2 1997/09/08 19:39:08 marklin Exp $";
/**
* Upon receiving this message the receiver should place any relevant
* state into <EM>state</EM>.
*/
public void storeState(Hashtable<Object,Object> state);
/**
* Upon receiving this message the receiver should extract any relevant
* state out of <EM>state</EM>.
*/
public void restoreState(Hashtable<?,?> state);
} // End of interface StateEditable

View File

@@ -0,0 +1,624 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing.undo;
import javax.swing.event.*;
import javax.swing.UIManager;
import java.util.*;
/**
* {@code UndoManager} manages a list of {@code UndoableEdits},
* providing a way to undo or redo the appropriate edits. There are
* two ways to add edits to an <code>UndoManager</code>. Add the edit
* directly using the <code>addEdit</code> method, or add the
* <code>UndoManager</code> to a bean that supports
* <code>UndoableEditListener</code>. The following examples creates
* an <code>UndoManager</code> and adds it as an
* <code>UndoableEditListener</code> to a <code>JTextField</code>:
* <pre>
* UndoManager undoManager = new UndoManager();
* JTextField tf = ...;
* tf.getDocument().addUndoableEditListener(undoManager);
* </pre>
* <p>
* <code>UndoManager</code> maintains an ordered list of edits and the
* index of the next edit in that list. The index of the next edit is
* either the size of the current list of edits, or if
* <code>undo</code> has been invoked it corresponds to the index
* of the last significant edit that was undone. When
* <code>undo</code> is invoked all edits from the index of the next
* edit to the last significant edit are undone, in reverse order.
* For example, consider an <code>UndoManager</code> consisting of the
* following edits: <b>A</b> <i>b</i> <i>c</i> <b>D</b>. Edits with a
* upper-case letter in bold are significant, those in lower-case
* and italicized are insignificant.
* <p>
* <a name="figure1"></a>
* <table border=0 summary="">
* <tr><td>
* <img src="doc-files/UndoManager-1.gif" alt="">
* <tr><td align=center>Figure 1
* </table>
* <p>
* As shown in <a href="#figure1">figure 1</a>, if <b>D</b> was just added, the
* index of the next edit will be 4. Invoking <code>undo</code>
* results in invoking <code>undo</code> on <b>D</b> and setting the
* index of the next edit to 3 (edit <i>c</i>), as shown in the following
* figure.
* <p>
* <a name="figure2"></a>
* <table border=0 summary="">
* <tr><td>
* <img src="doc-files/UndoManager-2.gif" alt="">
* <tr><td align=center>Figure 2
* </table>
* <p>
* The last significant edit is <b>A</b>, so that invoking
* <code>undo</code> again invokes <code>undo</code> on <i>c</i>,
* <i>b</i>, and <b>A</b>, in that order, setting the index of the
* next edit to 0, as shown in the following figure.
* <p>
* <a name="figure3"></a>
* <table border=0 summary="">
* <tr><td>
* <img src="doc-files/UndoManager-3.gif" alt="">
* <tr><td align=center>Figure 3
* </table>
* <p>
* Invoking <code>redo</code> results in invoking <code>redo</code> on
* all edits between the index of the next edit and the next
* significant edit (or the end of the list). Continuing with the previous
* example if <code>redo</code> were invoked, <code>redo</code> would in
* turn be invoked on <b>A</b>, <i>b</i> and <i>c</i>. In addition
* the index of the next edit is set to 3 (as shown in <a
* href="#figure2">figure 2</a>).
* <p>
* Adding an edit to an <code>UndoManager</code> results in
* removing all edits from the index of the next edit to the end of
* the list. Continuing with the previous example, if a new edit,
* <i>e</i>, is added the edit <b>D</b> is removed from the list
* (after having <code>die</code> invoked on it). If <i>c</i> is not
* incorporated by the next edit
* (<code><i>c</i>.addEdit(<i>e</i>)</code> returns true), or replaced
* by it (<code><i>e</i>.replaceEdit(<i>c</i>)</code> returns true),
* the new edit is added after <i>c</i>, as shown in the following
* figure.
* <p>
* <a name="figure4"></a>
* <table border=0 summary="">
* <tr><td>
* <img src="doc-files/UndoManager-4.gif" alt="">
* <tr><td align=center>Figure 4
* </table>
* <p>
* Once <code>end</code> has been invoked on an <code>UndoManager</code>
* the superclass behavior is used for all <code>UndoableEdit</code>
* methods. Refer to <code>CompoundEdit</code> for more details on its
* behavior.
* <p>
* Unlike the rest of Swing, this class is thread safe.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Ray Ryan
*/
public class UndoManager extends CompoundEdit implements UndoableEditListener {
int indexOfNextAdd;
int limit;
/**
* Creates a new <code>UndoManager</code>.
*/
public UndoManager() {
super();
indexOfNextAdd = 0;
limit = 100;
edits.ensureCapacity(limit);
}
/**
* Returns the maximum number of edits this {@code UndoManager}
* holds. A value less than 0 indicates the number of edits is not
* limited.
*
* @return the maximum number of edits this {@code UndoManager} holds
* @see #addEdit
* @see #setLimit
*/
public synchronized int getLimit() {
return limit;
}
/**
* Empties the undo manager sending each edit a <code>die</code> message
* in the process.
*
* @see AbstractUndoableEdit#die
*/
public synchronized void discardAllEdits() {
for (UndoableEdit e : edits) {
e.die();
}
edits = new Vector<UndoableEdit>();
indexOfNextAdd = 0;
// PENDING(rjrjr) when vector grows a removeRange() method
// (expected in JDK 1.2), trimEdits() will be nice and
// efficient, and this method can call that instead.
}
/**
* Reduces the number of queued edits to a range of size limit,
* centered on the index of the next edit.
*/
protected void trimForLimit() {
if (limit >= 0) {
int size = edits.size();
// System.out.print("limit: " + limit +
// " size: " + size +
// " indexOfNextAdd: " + indexOfNextAdd +
// "\n");
if (size > limit) {
int halfLimit = limit/2;
int keepFrom = indexOfNextAdd - 1 - halfLimit;
int keepTo = indexOfNextAdd - 1 + halfLimit;
// These are ints we're playing with, so dividing by two
// rounds down for odd numbers, so make sure the limit was
// honored properly. Note that the keep range is
// inclusive.
if (keepTo - keepFrom + 1 > limit) {
keepFrom++;
}
// The keep range is centered on indexOfNextAdd,
// but odds are good that the actual edits Vector
// isn't. Move the keep range to keep it legal.
if (keepFrom < 0) {
keepTo -= keepFrom;
keepFrom = 0;
}
if (keepTo >= size) {
int delta = size - keepTo - 1;
keepTo += delta;
keepFrom += delta;
}
// System.out.println("Keeping " + keepFrom + " " + keepTo);
trimEdits(keepTo+1, size-1);
trimEdits(0, keepFrom-1);
}
}
}
/**
* Removes edits in the specified range.
* All edits in the given range (inclusive, and in reverse order)
* will have <code>die</code> invoked on them and are removed from
* the list of edits. This has no effect if
* <code>from</code> &gt; <code>to</code>.
*
* @param from the minimum index to remove
* @param to the maximum index to remove
*/
protected void trimEdits(int from, int to) {
if (from <= to) {
// System.out.println("Trimming " + from + " " + to + " with index " +
// indexOfNextAdd);
for (int i = to; from <= i; i--) {
UndoableEdit e = edits.elementAt(i);
// System.out.println("JUM: Discarding " +
// e.getUndoPresentationName());
e.die();
// PENDING(rjrjr) when Vector supports range deletion (JDK
// 1.2) , we can optimize the next line considerably.
edits.removeElementAt(i);
}
if (indexOfNextAdd > to) {
// System.out.print("...right...");
indexOfNextAdd -= to-from+1;
} else if (indexOfNextAdd >= from) {
// System.out.println("...mid...");
indexOfNextAdd = from;
}
// System.out.println("new index " + indexOfNextAdd);
}
}
/**
* Sets the maximum number of edits this <code>UndoManager</code>
* holds. A value less than 0 indicates the number of edits is not
* limited. If edits need to be discarded to shrink the limit,
* <code>die</code> will be invoked on them in the reverse
* order they were added. The default is 100.
*
* @param l the new limit
* @throws RuntimeException if this {@code UndoManager} is not in progress
* ({@code end} has been invoked)
* @see #isInProgress
* @see #end
* @see #addEdit
* @see #getLimit
*/
public synchronized void setLimit(int l) {
if (!inProgress) throw new RuntimeException("Attempt to call UndoManager.setLimit() after UndoManager.end() has been called");
limit = l;
trimForLimit();
}
/**
* Returns the the next significant edit to be undone if <code>undo</code>
* is invoked. This returns <code>null</code> if there are no edits
* to be undone.
*
* @return the next significant edit to be undone
*/
protected UndoableEdit editToBeUndone() {
int i = indexOfNextAdd;
while (i > 0) {
UndoableEdit edit = edits.elementAt(--i);
if (edit.isSignificant()) {
return edit;
}
}
return null;
}
/**
* Returns the the next significant edit to be redone if <code>redo</code>
* is invoked. This returns <code>null</code> if there are no edits
* to be redone.
*
* @return the next significant edit to be redone
*/
protected UndoableEdit editToBeRedone() {
int count = edits.size();
int i = indexOfNextAdd;
while (i < count) {
UndoableEdit edit = edits.elementAt(i++);
if (edit.isSignificant()) {
return edit;
}
}
return null;
}
/**
* Undoes all changes from the index of the next edit to
* <code>edit</code>, updating the index of the next edit appropriately.
*
* @throws CannotUndoException if one of the edits throws
* <code>CannotUndoException</code>
*/
protected void undoTo(UndoableEdit edit) throws CannotUndoException {
boolean done = false;
while (!done) {
UndoableEdit next = edits.elementAt(--indexOfNextAdd);
next.undo();
done = next == edit;
}
}
/**
* Redoes all changes from the index of the next edit to
* <code>edit</code>, updating the index of the next edit appropriately.
*
* @throws CannotRedoException if one of the edits throws
* <code>CannotRedoException</code>
*/
protected void redoTo(UndoableEdit edit) throws CannotRedoException {
boolean done = false;
while (!done) {
UndoableEdit next = edits.elementAt(indexOfNextAdd++);
next.redo();
done = next == edit;
}
}
/**
* Convenience method that invokes one of <code>undo</code> or
* <code>redo</code>. If any edits have been undone (the index of
* the next edit is less than the length of the edits list) this
* invokes <code>redo</code>, otherwise it invokes <code>undo</code>.
*
* @see #canUndoOrRedo
* @see #getUndoOrRedoPresentationName
* @throws CannotUndoException if one of the edits throws
* <code>CannotUndoException</code>
* @throws CannotRedoException if one of the edits throws
* <code>CannotRedoException</code>
*/
public synchronized void undoOrRedo() throws CannotRedoException,
CannotUndoException {
if (indexOfNextAdd == edits.size()) {
undo();
} else {
redo();
}
}
/**
* Returns true if it is possible to invoke <code>undo</code> or
* <code>redo</code>.
*
* @return true if invoking <code>canUndoOrRedo</code> is valid
* @see #undoOrRedo
*/
public synchronized boolean canUndoOrRedo() {
if (indexOfNextAdd == edits.size()) {
return canUndo();
} else {
return canRedo();
}
}
/**
* Undoes the appropriate edits. If <code>end</code> has been
* invoked this calls through to the superclass, otherwise
* this invokes <code>undo</code> on all edits between the
* index of the next edit and the last significant edit, updating
* the index of the next edit appropriately.
*
* @throws CannotUndoException if one of the edits throws
* <code>CannotUndoException</code> or there are no edits
* to be undone
* @see CompoundEdit#end
* @see #canUndo
* @see #editToBeUndone
*/
public synchronized void undo() throws CannotUndoException {
if (inProgress) {
UndoableEdit edit = editToBeUndone();
if (edit == null) {
throw new CannotUndoException();
}
undoTo(edit);
} else {
super.undo();
}
}
/**
* Returns true if edits may be undone. If <code>end</code> has
* been invoked, this returns the value from super. Otherwise
* this returns true if there are any edits to be undone
* (<code>editToBeUndone</code> returns non-<code>null</code>).
*
* @return true if there are edits to be undone
* @see CompoundEdit#canUndo
* @see #editToBeUndone
*/
public synchronized boolean canUndo() {
if (inProgress) {
UndoableEdit edit = editToBeUndone();
return edit != null && edit.canUndo();
} else {
return super.canUndo();
}
}
/**
* Redoes the appropriate edits. If <code>end</code> has been
* invoked this calls through to the superclass. Otherwise
* this invokes <code>redo</code> on all edits between the
* index of the next edit and the next significant edit, updating
* the index of the next edit appropriately.
*
* @throws CannotRedoException if one of the edits throws
* <code>CannotRedoException</code> or there are no edits
* to be redone
* @see CompoundEdit#end
* @see #canRedo
* @see #editToBeRedone
*/
public synchronized void redo() throws CannotRedoException {
if (inProgress) {
UndoableEdit edit = editToBeRedone();
if (edit == null) {
throw new CannotRedoException();
}
redoTo(edit);
} else {
super.redo();
}
}
/**
* Returns true if edits may be redone. If <code>end</code> has
* been invoked, this returns the value from super. Otherwise,
* this returns true if there are any edits to be redone
* (<code>editToBeRedone</code> returns non-<code>null</code>).
*
* @return true if there are edits to be redone
* @see CompoundEdit#canRedo
* @see #editToBeRedone
*/
public synchronized boolean canRedo() {
if (inProgress) {
UndoableEdit edit = editToBeRedone();
return edit != null && edit.canRedo();
} else {
return super.canRedo();
}
}
/**
* Adds an <code>UndoableEdit</code> to this
* <code>UndoManager</code>, if it's possible. This removes all
* edits from the index of the next edit to the end of the edits
* list. If <code>end</code> has been invoked the edit is not added
* and <code>false</code> is returned. If <code>end</code> hasn't
* been invoked this returns <code>true</code>.
*
* @param anEdit the edit to be added
* @return true if <code>anEdit</code> can be incorporated into this
* edit
* @see CompoundEdit#end
* @see CompoundEdit#addEdit
*/
public synchronized boolean addEdit(UndoableEdit anEdit) {
boolean retVal;
// Trim from the indexOfNextAdd to the end, as we'll
// never reach these edits once the new one is added.
trimEdits(indexOfNextAdd, edits.size()-1);
retVal = super.addEdit(anEdit);
if (inProgress) {
retVal = true;
}
// Maybe super added this edit, maybe it didn't (perhaps
// an in progress compound edit took it instead. Or perhaps
// this UndoManager is no longer in progress). So make sure
// the indexOfNextAdd is pointed at the right place.
indexOfNextAdd = edits.size();
// Enforce the limit
trimForLimit();
return retVal;
}
/**
* Turns this <code>UndoManager</code> into a normal
* <code>CompoundEdit</code>. This removes all edits that have
* been undone.
*
* @see CompoundEdit#end
*/
public synchronized void end() {
super.end();
this.trimEdits(indexOfNextAdd, edits.size()-1);
}
/**
* Convenience method that returns either
* <code>getUndoPresentationName</code> or
* <code>getRedoPresentationName</code>. If the index of the next
* edit equals the size of the edits list,
* <code>getUndoPresentationName</code> is returned, otherwise
* <code>getRedoPresentationName</code> is returned.
*
* @return undo or redo name
*/
public synchronized String getUndoOrRedoPresentationName() {
if (indexOfNextAdd == edits.size()) {
return getUndoPresentationName();
} else {
return getRedoPresentationName();
}
}
/**
* Returns a description of the undoable form of this edit.
* If <code>end</code> has been invoked this calls into super.
* Otherwise if there are edits to be undone, this returns
* the value from the next significant edit that will be undone.
* If there are no edits to be undone and <code>end</code> has not
* been invoked this returns the value from the <code>UIManager</code>
* property "AbstractUndoableEdit.undoText".
*
* @return a description of the undoable form of this edit
* @see #undo
* @see CompoundEdit#getUndoPresentationName
*/
public synchronized String getUndoPresentationName() {
if (inProgress) {
if (canUndo()) {
return editToBeUndone().getUndoPresentationName();
} else {
return UIManager.getString("AbstractUndoableEdit.undoText");
}
} else {
return super.getUndoPresentationName();
}
}
/**
* Returns a description of the redoable form of this edit.
* If <code>end</code> has been invoked this calls into super.
* Otherwise if there are edits to be redone, this returns
* the value from the next significant edit that will be redone.
* If there are no edits to be redone and <code>end</code> has not
* been invoked this returns the value from the <code>UIManager</code>
* property "AbstractUndoableEdit.redoText".
*
* @return a description of the redoable form of this edit
* @see #redo
* @see CompoundEdit#getRedoPresentationName
*/
public synchronized String getRedoPresentationName() {
if (inProgress) {
if (canRedo()) {
return editToBeRedone().getRedoPresentationName();
} else {
return UIManager.getString("AbstractUndoableEdit.redoText");
}
} else {
return super.getRedoPresentationName();
}
}
/**
* An <code>UndoableEditListener</code> method. This invokes
* <code>addEdit</code> with <code>e.getEdit()</code>.
*
* @param e the <code>UndoableEditEvent</code> the
* <code>UndoableEditEvent</code> will be added from
* @see #addEdit
*/
public void undoableEditHappened(UndoableEditEvent e) {
addEdit(e.getEdit());
}
/**
* Returns a string that displays and identifies this
* object's properties.
*
* @return a String representation of this object
*/
public String toString() {
return super.toString() + " limit: " + limit +
" indexOfNextAdd: " + indexOfNextAdd;
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing.undo;
import javax.swing.event.*;
/**
* An <code>UndoableEdit</code> represents an edit. The edit may
* be undone, or if already undone the edit may be redone.
* <p>
* <code>UndoableEdit</code> is designed to be used with the
* <code>UndoManager</code>. As <code>UndoableEdit</code>s are generated
* by an <code>UndoableEditListener</code> they are typically added to
* the <code>UndoManager</code>. When an <code>UndoableEdit</code>
* is added to an <code>UndoManager</code> the following occurs (assuming
* <code>end</code> has not been called on the <code>UndoManager</code>):
* <ol>
* <li>If the <code>UndoManager</code> contains edits it will call
* <code>addEdit</code> on the current edit passing in the new edit
* as the argument. If <code>addEdit</code> returns true the
* new edit is assumed to have been incorporated into the current edit and
* the new edit will not be added to the list of current edits.
* Edits can use <code>addEdit</code> as a way for smaller edits to
* be incorporated into a larger edit and treated as a single edit.
* <li>If <code>addEdit</code> returns false <code>replaceEdit</code>
* is called on the new edit with the current edit passed in as the
* argument. This is the inverse of <code>addEdit</code> &#151;
* if the new edit returns true from <code>replaceEdit</code>, the new
* edit replaces the current edit.
* </ol>
* The <code>UndoManager</code> makes use of
* <code>isSignificant</code> to determine how many edits should be
* undone or redone. The <code>UndoManager</code> will undo or redo
* all insignificant edits (<code>isSignificant</code> returns false)
* between the current edit and the last or
* next significant edit. <code>addEdit</code> and
* <code>replaceEdit</code> can be used to treat multiple edits as
* a single edit, returning false from <code>isSignificant</code>
* allows for treating can be used to
* have many smaller edits undone or redone at once. Similar functionality
* can also be done using the <code>addEdit</code> method.
*
* @author Ray Ryan
*/
public interface UndoableEdit {
/**
* Undo the edit.
*
* @throws CannotUndoException if this edit can not be undone
*/
public void undo() throws CannotUndoException;
/**
* Returns true if this edit may be undone.
*
* @return true if this edit may be undone
*/
public boolean canUndo();
/**
* Re-applies the edit.
*
* @throws CannotRedoException if this edit can not be redone
*/
public void redo() throws CannotRedoException;
/**
* Returns true if this edit may be redone.
*
* @return true if this edit may be redone
*/
public boolean canRedo();
/**
* Informs the edit that it should no longer be used. Once an
* <code>UndoableEdit</code> has been marked as dead it can no longer
* be undone or redone.
* <p>
* This is a useful hook for cleaning up state no longer
* needed once undoing or redoing is impossible--for example,
* deleting file resources used by objects that can no longer be
* undeleted. <code>UndoManager</code> calls this before it dequeues edits.
* <p>
* Note that this is a one-way operation. There is no "un-die"
* method.
*
* @see CompoundEdit#die
*/
public void die();
/**
* Adds an <code>UndoableEdit</code> to this <code>UndoableEdit</code>.
* This method can be used to coalesce smaller edits into a larger
* compound edit. For example, text editors typically allow
* undo operations to apply to words or sentences. The text
* editor may choose to generate edits on each key event, but allow
* those edits to be coalesced into a more user-friendly unit, such as
* a word. In this case, the <code>UndoableEdit</code> would
* override <code>addEdit</code> to return true when the edits may
* be coalesced.
* <p>
* A return value of true indicates <code>anEdit</code> was incorporated
* into this edit. A return value of false indicates <code>anEdit</code>
* may not be incorporated into this edit.
* <p>Typically the receiver is already in the queue of a
* <code>UndoManager</code> (or other <code>UndoableEditListener</code>),
* and is being given a chance to incorporate <code>anEdit</code>
* rather than letting it be added to the queue in turn.</p>
*
* <p>If true is returned, from now on <code>anEdit</code> must return
* false from <code>canUndo</code> and <code>canRedo</code>,
* and must throw the appropriate exception on <code>undo</code> or
* <code>redo</code>.</p>
*
* @param anEdit the edit to be added
* @return true if <code>anEdit</code> may be incorporated into this
* edit
*/
public boolean addEdit(UndoableEdit anEdit);
/**
* Returns true if this <code>UndoableEdit</code> should replace
* <code>anEdit</code>. This method is used by <code>CompoundEdit</code>
* and the <code>UndoManager</code>; it is called if
* <code>anEdit</code> could not be added to the current edit
* (<code>addEdit</code> returns false).
* <p>
* This method provides a way for an edit to replace an existing edit.
* <p>This message is the opposite of addEdit--anEdit has typically
* already been queued in an <code>UndoManager</code> (or other
* UndoableEditListener), and the receiver is being given a chance
* to take its place.</p>
*
* <p>If true is returned, from now on anEdit must return false from
* canUndo() and canRedo(), and must throw the appropriate
* exception on undo() or redo().</p>
*
* @param anEdit the edit that replaces the current edit
* @return true if this edit should replace <code>anEdit</code>
*/
public boolean replaceEdit(UndoableEdit anEdit);
/**
* Returns true if this edit is considered significant. A significant
* edit is typically an edit that should be presented to the user, perhaps
* on a menu item or tooltip. The <code>UndoManager</code> will undo,
* or redo, all insignificant edits to the next significant edit.
*
* @return true if this edit is significant
*/
public boolean isSignificant();
/**
* Returns a localized, human-readable description of this edit, suitable
* for use in a change log, for example.
*
* @return description of this edit
*/
public String getPresentationName();
/**
* Returns a localized, human-readable description of the undoable form of
* this edit, suitable for use as an Undo menu item, for example.
* This is typically derived from <code>getPresentationName</code>.
*
* @return a description of the undoable form of this edit
*/
public String getUndoPresentationName();
/**
* Returns a localized, human-readable description of the redoable form of
* this edit, suitable for use as a Redo menu item, for example. This is
* typically derived from <code>getPresentationName</code>.
*
* @return a description of the redoable form of this edit
*/
public String getRedoPresentationName();
}

View File

@@ -0,0 +1,176 @@
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing.undo;
import javax.swing.event.*;
import java.util.*;
/**
* A support class used for managing <code>UndoableEdit</code> listeners.
*
* @author Ray Ryan
*/
public class UndoableEditSupport {
protected int updateLevel;
protected CompoundEdit compoundEdit;
protected Vector<UndoableEditListener> listeners;
protected Object realSource;
/**
* Constructs an <code>UndoableEditSupport</code> object.
*/
public UndoableEditSupport() {
this(null);
}
/**
* Constructs an <code>UndoableEditSupport</code> object.
*
* @param r an <code>Object</code>
*/
public UndoableEditSupport(Object r) {
realSource = r == null ? this : r;
updateLevel = 0;
compoundEdit = null;
listeners = new Vector<UndoableEditListener>();
}
/**
* Registers an <code>UndoableEditListener</code>.
* The listener is notified whenever an edit occurs which can be undone.
*
* @param l an <code>UndoableEditListener</code> object
* @see #removeUndoableEditListener
*/
public synchronized void addUndoableEditListener(UndoableEditListener l) {
listeners.addElement(l);
}
/**
* Removes an <code>UndoableEditListener</code>.
*
* @param l the <code>UndoableEditListener</code> object to be removed
* @see #addUndoableEditListener
*/
public synchronized void removeUndoableEditListener(UndoableEditListener l)
{
listeners.removeElement(l);
}
/**
* Returns an array of all the <code>UndoableEditListener</code>s added
* to this UndoableEditSupport with addUndoableEditListener().
*
* @return all of the <code>UndoableEditListener</code>s added or an empty
* array if no listeners have been added
* @since 1.4
*/
public synchronized UndoableEditListener[] getUndoableEditListeners() {
return listeners.toArray(new UndoableEditListener[0]);
}
/**
* Called only from <code>postEdit</code> and <code>endUpdate</code>. Calls
* <code>undoableEditHappened</code> in all listeners. No synchronization
* is performed here, since the two calling methods are synchronized.
*/
protected void _postEdit(UndoableEdit e) {
UndoableEditEvent ev = new UndoableEditEvent(realSource, e);
Enumeration cursor = ((Vector)listeners.clone()).elements();
while (cursor.hasMoreElements()) {
((UndoableEditListener)cursor.nextElement()).
undoableEditHappened(ev);
}
}
/**
* DEADLOCK WARNING: Calling this method may call
* <code>undoableEditHappened</code> in all listeners.
* It is unwise to call this method from one of its listeners.
*/
public synchronized void postEdit(UndoableEdit e) {
if (updateLevel == 0) {
_postEdit(e);
} else {
// PENDING(rjrjr) Throw an exception if this fails?
compoundEdit.addEdit(e);
}
}
/**
* Returns the update level value.
*
* @return an integer representing the update level
*/
public int getUpdateLevel() {
return updateLevel;
}
/**
*
*/
public synchronized void beginUpdate() {
if (updateLevel == 0) {
compoundEdit = createCompoundEdit();
}
updateLevel++;
}
/**
* Called only from <code>beginUpdate</code>.
* Exposed here for subclasses' use.
*/
protected CompoundEdit createCompoundEdit() {
return new CompoundEdit();
}
/**
* DEADLOCK WARNING: Calling this method may call
* <code>undoableEditHappened</code> in all listeners.
* It is unwise to call this method from one of its listeners.
*/
public synchronized void endUpdate() {
updateLevel--;
if (updateLevel == 0) {
compoundEdit.end();
_postEdit(compoundEdit);
compoundEdit = null;
}
}
/**
* Returns a string that displays and identifies this
* object's properties.
*
* @return a <code>String</code> representation of this object
*/
public String toString() {
return super.toString() +
" updateLevel: " + updateLevel +
" listeners: " + listeners +
" compoundEdit: " + compoundEdit;
}
}