Source for javax.swing.undo.StateEdit

   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>&#x2019;s implementation of {@link
  60:  * StateEditable} considers the name as part of the editable state,
  61:  * the user can now choose &#x201c;Undo Name Change&#x201d; or
  62:  * &#x201c;Redo Name Change&#x201d; 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&#x2019;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&#x2019;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();
 181:     postState = new Hashtable();
 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 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: }