Frames | No Frames |
1: /* StateEdit.java -- UndoableEdit for StateEditable implementations. 2: Copyright (C) 2002, 2003 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.undo; 40: 41: import java.util.Hashtable; 42: import java.util.Iterator; 43: 44: /** 45: * A helper class, making it easy to support undo and redo. 46: * 47: * <p>The following example shows how to use this class.</p> 48: * 49: * <pre> 50: * Foo foo; // class Foo implements {@link StateEditable} 51: * StateEdit edit; 52: * 53: * edit = new StateEdit(foo, "Name Change"); 54: * foo.setName("Jane Doe"); 55: * edit.end(); 56: * undoManager.addEdit(edit); 57: * </pre> 58: * 59: * <p>If <code>Foo</code>’s implementation of {@link 60: * StateEditable} considers the name as part of the editable state, 61: * the user can now choose “Undo Name Change” or 62: * “Redo Name Change” from the respective menu. No 63: * further undo support is needed from the application.</p> 64: * 65: * <p>The following explains what happens in the example.</p> 66: * 67: * <ol> 68: * <li>When a <code>StateEdit</code> is created, the associated 69: * {@link StateEditable} gets asked to store its state into a hash 70: * table, {@link #preState}.</li> 71: * <li>The application will now perform some changes to the edited 72: * object. This typically happens by invoking methods on the edited 73: * object.</li> 74: * <li>The editing phase is terminated by invoking the {@link #end()} 75: * method of the <code>StateEdit</code>. The <code>end()</code> method 76: * does two things. 77: * 78: * <ul> 79: * <li>The edited object receives a second request for storing 80: * its state. This time, it will use a different hash table, {@link 81: * #postState}.</li> 82: * <li>To increase efficiency, the <code>StateEdit</code> now removes 83: * any entries from {@link #preState} and {@link #postState} that have 84: * the same key, and whose values are equal. Equality is determined 85: * by invoking the <code>equals</code> method inherited from 86: * {@link java.lang.Object}.</li> 87: * </ul></li> 88: * <li>When the user later chooses to undo the <code>StateEdit</code>, 89: * the edited object is asked to {@linkplain StateEditable#restoreState 90: * restore its state} from the {@link #preState} table. Similarly, 91: * when the user chooses to <i>redo</i> the <code>StateEdit</code>, 92: * the edited object gets asked to restore its state from the {@link 93: * #postState}.</li> 94: * </ol> 95: * 96: * @author Andrew Selkirk (aselkirk@sympatico.ca) 97: * @author Sascha Brawer (brawer@dandelis.ch) 98: */ 99: public class StateEdit 100: extends AbstractUndoableEdit 101: { 102: /** 103: * The ID of the Java source file in Sun’s Revision Control 104: * System (RCS). This certainly should not be part of the API 105: * specification. But in order to be API-compatible with 106: * Sun’s reference implementation, GNU Classpath also has to 107: * provide this field and match its value. The value used here has 108: * been in every JDK release at least from 1.2 to 1.5. 109: */ 110: protected static final String RCSID = "$" + 111: "Id: StateEdit.java,v 1.6 1997/10/01 20:05:51 sandipc Exp $"; 112: 113: 114: /** 115: * The object which is being edited by this <code>StateEdit</code>. 116: */ 117: protected StateEditable object; 118: 119: 120: /** 121: * The state of <code>object</code> at the time of constructing 122: * this <code>StateEdit</code>. 123: */ 124: protected Hashtable<Object, Object> preState; 125: 126: 127: /** 128: * The state of <code>object</code> at the time when {@link #end()} 129: * was called. 130: */ 131: protected Hashtable<Object, Object> postState; 132: 133: 134: /** 135: * A human-readable name for this edit action. 136: */ 137: protected String undoRedoName; 138: 139: 140: /** 141: * Constructs a <code>StateEdit</code>, specifying the object whose 142: * state is being edited. 143: * 144: * @param obj the object whose state is being edited by this 145: * <code>StateEdit</code>. 146: */ 147: public StateEdit(StateEditable obj) 148: { 149: init(obj, null); 150: } 151: 152: 153: /** 154: * Constructs a <code>StateEdit</code>, specifying the object whose 155: * state is being edited. 156: * 157: * @param obj the object whose state is being edited by this 158: * <code>StateEdit</code>. 159: * 160: * @param name the human-readable name of the editing action. 161: */ 162: public StateEdit(StateEditable obj, String name) 163: { 164: init(obj, name); 165: } 166: 167: 168: /** 169: * Initializes this <code>StateEdit</code>. The edited object will 170: * be asked to store its current state into {@link #preState}. 171: * 172: * @param obj the object being edited. 173: * 174: * @param name the human-readable name of the editing action. 175: */ 176: protected void init(StateEditable obj, String name) 177: { 178: object = obj; 179: undoRedoName = name; 180: preState = new Hashtable<Object,Object>(); 181: postState = new Hashtable<Object,Object>(); 182: obj.storeState(preState); 183: } 184: 185: 186: /** 187: * Informs this <code>StateEdit</code> that all edits are finished. 188: * The edited object will be asked to store its state into {@link 189: * #postState}, and any redundant entries will get removed from 190: * {@link #preState} and {@link #postState}. 191: */ 192: public void end() 193: { 194: object.storeState(postState); 195: removeRedundantState(); 196: } 197: 198: 199: /** 200: * Undoes this edit operation. The edited object will be asked to 201: * {@linkplain StateEditable#restoreState restore its state} from 202: * {@link #preState}. 203: * 204: * @throws CannotUndoException if {@link #canUndo()} returns 205: * <code>false</code>, for example because this action has already 206: * been undone. 207: */ 208: public void undo() 209: { 210: super.undo(); 211: object.restoreState(preState); 212: } 213: 214: 215: /** 216: * Redoes this edit operation. The edited object will be asked to 217: * {@linkplain StateEditable#restoreState restore its state} from 218: * {@link #postState}. 219: * 220: * @throws CannotRedoException if {@link #canRedo()} returns 221: * <code>false</code>, for example because this action has not yet 222: * been undone. 223: */ 224: public void redo() 225: { 226: super.redo(); 227: object.restoreState(postState); 228: } 229: 230: 231: /** 232: * Returns a human-readable, localized name that describes this 233: * editing action and can be displayed to the user. 234: * 235: * @return the name, or <code>null</code> if no presentation 236: * name is available. 237: */ 238: public String getPresentationName() 239: { 240: return undoRedoName; 241: } 242: 243: 244: /** 245: * Removes all redundant entries from the pre- and post-edit state 246: * hash tables. An entry is considered redundant if it is present 247: * both before and after the edit, and if the two values are equal. 248: */ 249: protected void removeRedundantState() 250: { 251: Iterator<Object> i = preState.keySet().iterator(); 252: while (i.hasNext()) 253: { 254: Object key = i.next(); 255: if (postState.containsKey(key)) 256: { 257: if (preState.get(key).equals(postState.get(key))) 258: { 259: i.remove(); 260: postState.remove(key); 261: } 262: } 263: } 264: } 265: }