1 /*
2  * Copyright (c) 1997, 2015, 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     /**
63      * Obsolete RCS version identity.
64      */
65     protected static final String RCSID = "$Id: StateEdit.java,v 1.6 1997/10/01 20:05:51 sandipc Exp $";
66 
67     //
68     // Attributes
69     //
70 
71     /**
72      * The object being edited
73      */
74     protected StateEditable object;
75 
76     /**
77      * The state information prior to the edit
78      */
79     protected Hashtable<Object,Object> preState;
80 
81     /**
82      * The state information after the edit
83      */
84     protected Hashtable<Object,Object> postState;
85 
86     /**
87      * The undo/redo presentation name
88      */
89     protected String undoRedoName;
90 
91     //
92     // Constructors
93     //
94 
95     /**
96      * Create and return a new StateEdit.
97      *
98      * @param anObject The object to watch for changing state
99      *
100      * @see StateEdit
101      */
StateEdit(StateEditable anObject)102     public StateEdit(StateEditable anObject) {
103         super();
104         init (anObject,null);
105     }
106 
107     /**
108      * Create and return a new StateEdit with a presentation name.
109      *
110      * @param anObject The object to watch for changing state
111      * @param name The presentation name to be used for this edit
112      *
113      * @see StateEdit
114      */
StateEdit(StateEditable anObject, String name)115     public StateEdit(StateEditable anObject, String name) {
116         super();
117         init (anObject,name);
118     }
119 
120     /**
121      * Initialize the state edit.
122      * @param anObject The object to watch for changing state
123      * @param name The presentation name to be used for this edit
124      */
init(StateEditable anObject, String name)125     protected void init (StateEditable anObject, String name) {
126         this.object = anObject;
127         this.preState = new Hashtable<Object, Object>(11);
128         this.object.storeState(this.preState);
129         this.postState = null;
130         this.undoRedoName = name;
131     }
132 
133 
134     //
135     // Operation
136     //
137 
138 
139     /**
140      * Gets the post-edit state of the StateEditable object and
141      * ends the edit.
142      */
end()143     public void end() {
144         this.postState = new Hashtable<Object, Object>(11);
145         this.object.storeState(this.postState);
146         this.removeRedundantState();
147     }
148 
149     /**
150      * Tells the edited object to apply the state prior to the edit
151      */
undo()152     public void undo() {
153         super.undo();
154         this.object.restoreState(preState);
155     }
156 
157     /**
158      * Tells the edited object to apply the state after the edit
159      */
redo()160     public void redo() {
161         super.redo();
162         this.object.restoreState(postState);
163     }
164 
165     /**
166      * Gets the presentation name for this edit
167      */
getPresentationName()168     public String getPresentationName() {
169         return this.undoRedoName;
170     }
171 
172 
173     //
174     // Internal support
175     //
176 
177     /**
178      * Remove redundant key/values in state hashtables.
179      */
removeRedundantState()180     protected void removeRedundantState() {
181         Vector<Object> uselessKeys = new Vector<>();
182         Enumeration<Object> myKeys = preState.keys();
183 
184         // Locate redundant state
185         while (myKeys.hasMoreElements()) {
186             Object myKey = myKeys.nextElement();
187             if (postState.containsKey(myKey) &&
188                 postState.get(myKey).equals(preState.get(myKey))) {
189                 uselessKeys.addElement(myKey);
190             }
191         }
192 
193         // Remove redundant state
194         for (int i = uselessKeys.size()-1; i >= 0; i--) {
195             Object myKey = uselessKeys.elementAt(i);
196             preState.remove(myKey);
197             postState.remove(myKey);
198         }
199     }
200 
201 } // End of class StateEdit
202