1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing.undo;
  27 
  28 import java.util.Enumeration;
  29 import java.util.Hashtable;
  30 import java.util.Vector;
  31 
  32 /**
  33  * <P>StateEdit is a general edit for objects that change state.
  34  * Objects being edited must conform to the StateEditable interface.</P>
  35  *
  36  * <P>This edit class works by asking an object to store it's state in
  37  * Hashtables before and after editing occurs.  Upon undo or redo the
  38  * object is told to restore it's state from these Hashtables.</P>
  39  *
  40  * A state edit is used as follows:
  41  * <PRE>
  42  *      // Create the edit during the "before" state of the object
  43  *      StateEdit newEdit = new StateEdit(myObject);
  44  *      // Modify the object
  45  *      myObject.someStateModifyingMethod();
  46  *      // "end" the edit when you are done modifying the object
  47  *      newEdit.end();
  48  * </PRE>
  49  *
  50  * <P><EM>Note that when a StateEdit ends, it removes redundant state from
  51  * the Hashtables - A state Hashtable is not guaranteed to contain all
  52  * keys/values placed into it when the state is stored!</EM></P>
  53  *
  54  * @see StateEditable
  55  *
  56  * @author Ray Ryan
  57  */
  58 @SuppressWarnings("serial") // Same-version serialization only
  59 public class StateEdit
  60         extends AbstractUndoableEdit {
  61 
  62     protected static final String RCSID = "$Id: StateEdit.java,v 1.6 1997/10/01 20:05:51 sandipc Exp $";
  63 
  64     //
  65     // Attributes
  66     //
  67 
  68     /**
  69      * The object being edited
  70      */
  71     protected StateEditable object;
  72 
  73     /**
  74      * The state information prior to the edit
  75      */
  76     protected Hashtable<Object,Object> preState;
  77 
  78     /**
  79      * The state information after the edit
  80      */
  81     protected Hashtable<Object,Object> postState;
  82 
  83     /**
  84      * The undo/redo presentation name
  85      */
  86     protected String undoRedoName;
  87 
  88     //
  89     // Constructors
  90     //
  91 
  92     /**
  93      * Create and return a new StateEdit.
  94      *
  95      * @param anObject The object to watch for changing state
  96      *
  97      * @see StateEdit
  98      */
  99     public StateEdit(StateEditable anObject) {
 100         super();
 101         init (anObject,null);
 102     }
 103 
 104     /**
 105      * Create and return a new StateEdit with a presentation name.
 106      *
 107      * @param anObject The object to watch for changing state
 108      * @param name The presentation name to be used for this edit
 109      *
 110      * @see StateEdit
 111      */
 112     public StateEdit(StateEditable anObject, String name) {
 113         super();
 114         init (anObject,name);
 115     }
 116 
 117     protected void init (StateEditable anObject, String name) {
 118         this.object = anObject;
 119         this.preState = new Hashtable<Object, Object>(11);
 120         this.object.storeState(this.preState);
 121         this.postState = null;
 122         this.undoRedoName = name;
 123     }
 124 
 125 
 126     //
 127     // Operation
 128     //
 129 
 130 
 131     /**
 132      * Gets the post-edit state of the StateEditable object and
 133      * ends the edit.
 134      */
 135     public void end() {
 136         this.postState = new Hashtable<Object, Object>(11);
 137         this.object.storeState(this.postState);
 138         this.removeRedundantState();
 139     }
 140 
 141     /**
 142      * Tells the edited object to apply the state prior to the edit
 143      */
 144     public void undo() {
 145         super.undo();
 146         this.object.restoreState(preState);
 147     }
 148 
 149     /**
 150      * Tells the edited object to apply the state after the edit
 151      */
 152     public void redo() {
 153         super.redo();
 154         this.object.restoreState(postState);
 155     }
 156 
 157     /**
 158      * Gets the presentation name for this edit
 159      */
 160     public String getPresentationName() {
 161         return this.undoRedoName;
 162     }
 163 
 164 
 165     //
 166     // Internal support
 167     //
 168 
 169     /**
 170      * Remove redundant key/values in state hashtables.
 171      */
 172     protected void removeRedundantState() {
 173         Vector<Object> uselessKeys = new Vector<Object>();
 174         Enumeration myKeys = preState.keys();
 175 
 176         // Locate redundant state
 177         while (myKeys.hasMoreElements()) {
 178             Object myKey = myKeys.nextElement();
 179             if (postState.containsKey(myKey) &&
 180                 postState.get(myKey).equals(preState.get(myKey))) {
 181                 uselessKeys.addElement(myKey);
 182             }
 183         }
 184 
 185         // Remove redundant state
 186         for (int i = uselessKeys.size()-1; i >= 0; i--) {
 187             Object myKey = uselessKeys.elementAt(i);
 188             preState.remove(myKey);
 189             postState.remove(myKey);
 190         }
 191     }
 192 
 193 } // End of class StateEdit