1 /*
2 * Copyright 1997-2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25 package javax.swing.undo;
26
27 import java.util;
28
29 /**
30 * A concrete subclass of AbstractUndoableEdit, used to assemble little
31 * UndoableEdits into great big ones.
32 *
33 * @author Ray Ryan
34 */
35 public class CompoundEdit extends AbstractUndoableEdit {
36 /**
37 * True if this edit has never received <code>end</code>.
38 */
39 boolean inProgress;
40
41 /**
42 * The collection of <code>UndoableEdit</code>s
43 * undone/redone en masse by this <code>CompoundEdit</code>.
44 */
45 protected Vector<UndoableEdit> edits;
46
47 public CompoundEdit() {
48 super();
49 inProgress = true;
50 edits = new Vector<UndoableEdit>();
51 }
52
53 /**
54 * Sends <code>undo</code> to all contained
55 * <code>UndoableEdits</code> in the reverse of
56 * the order in which they were added.
57 */
58 public void undo() throws CannotUndoException {
59 super.undo();
60 int i = edits.size();
61 while (i-- > 0) {
62 UndoableEdit e = (UndoableEdit)edits.elementAt(i);
63 e.undo();
64 }
65 }
66
67 /**
68 * Sends <code>redo</code> to all contained
69 * <code>UndoableEdit</code>s in the order in
70 * which they were added.
71 */
72 public void redo() throws CannotRedoException {
73 super.redo();
74 Enumeration cursor = edits.elements();
75 while (cursor.hasMoreElements()) {
76 ((UndoableEdit)cursor.nextElement()).redo();
77 }
78 }
79
80 /**
81 * Returns the last <code>UndoableEdit</code> in
82 * <code>edits</code>, or <code>null</code>
83 * if <code>edits</code> is empty.
84 */
85 protected UndoableEdit lastEdit() {
86 int count = edits.size();
87 if (count > 0)
88 return (UndoableEdit)edits.elementAt(count-1);
89 else
90 return null;
91 }
92
93 /**
94 * Sends <code>die</code> to each subedit,
95 * in the reverse of the order that they were added.
96 */
97 public void die() {
98 int size = edits.size();
99 for (int i = size-1; i >= 0; i--)
100 {
101 UndoableEdit e = (UndoableEdit)edits.elementAt(i);
102 // System.out.println("CompoundEdit(" + i + "): Discarding " +
103 // e.getUndoPresentationName());
104 e.die();
105 }
106 super.die();
107 }
108
109 /**
110 * If this edit is <code>inProgress</code>,
111 * accepts <code>anEdit</code> and returns true.
112 *
113 * <p>The last edit added to this <code>CompoundEdit</code>
114 * is given a chance to <code>addEdit(anEdit)</code>.
115 * If it refuses (returns false), <code>anEdit</code> is
116 * given a chance to <code>replaceEdit</code> the last edit.
117 * If <code>anEdit</code> returns false here,
118 * it is added to <code>edits</code>.
119 *
120 * @param anEdit the edit to be added
121 * @return true if the edit is <code>inProgress</code>;
122 * otherwise returns false
123 */
124 public boolean addEdit(UndoableEdit anEdit) {
125 if (!inProgress) {
126 return false;
127 } else {
128 UndoableEdit last = lastEdit();
129
130 // If this is the first subedit received, just add it.
131 // Otherwise, give the last one a chance to absorb the new
132 // one. If it won't, give the new one a chance to absorb
133 // the last one.
134
135 if (last == null) {
136 edits.addElement(anEdit);
137 }
138 else if (!last.addEdit(anEdit)) {
139 if (anEdit.replaceEdit(last)) {
140 edits.removeElementAt(edits.size()-1);
141 }
142 edits.addElement(anEdit);
143 }
144
145 return true;
146 }
147 }
148
149 /**
150 * Sets <code>inProgress</code> to false.
151 *
152 * @see #canUndo
153 * @see #canRedo
154 */
155 public void end() {
156 inProgress = false;
157 }
158
159 /**
160 * Returns false if <code>isInProgress</code> or if super
161 * returns false.
162 *
163 * @see #isInProgress
164 */
165 public boolean canUndo() {
166 return !isInProgress() && super.canUndo();
167 }
168
169 /**
170 * Returns false if <code>isInProgress</code> or if super
171 * returns false.
172 *
173 * @see #isInProgress
174 */
175 public boolean canRedo() {
176 return !isInProgress() && super.canRedo();
177 }
178
179 /**
180 * Returns true if this edit is in progress--that is, it has not
181 * received end. This generally means that edits are still being
182 * added to it.
183 *
184 * @see #end
185 */
186 public boolean isInProgress() {
187 return inProgress;
188 }
189
190 /**
191 * Returns true if any of the <code>UndoableEdit</code>s
192 * in <code>edits</code> do.
193 * Returns false if they all return false.
194 */
195 public boolean isSignificant() {
196 Enumeration cursor = edits.elements();
197 while (cursor.hasMoreElements()) {
198 if (((UndoableEdit)cursor.nextElement()).isSignificant()) {
199 return true;
200 }
201 }
202 return false;
203 }
204
205 /**
206 * Returns <code>getPresentationName</code> from the
207 * last <code>UndoableEdit</code> added to
208 * <code>edits</code>. If <code>edits</code> is empty,
209 * calls super.
210 */
211 public String getPresentationName() {
212 UndoableEdit last = lastEdit();
213 if (last != null) {
214 return last.getPresentationName();
215 } else {
216 return super.getPresentationName();
217 }
218 }
219
220 /**
221 * Returns <code>getUndoPresentationName</code>
222 * from the last <code>UndoableEdit</code>
223 * added to <code>edits</code>.
224 * If <code>edits</code> is empty, calls super.
225 */
226 public String getUndoPresentationName() {
227 UndoableEdit last = lastEdit();
228 if (last != null) {
229 return last.getUndoPresentationName();
230 } else {
231 return super.getUndoPresentationName();
232 }
233 }
234
235 /**
236 * Returns <code>getRedoPresentationName</code>
237 * from the last <code>UndoableEdit</code>
238 * added to <code>edits</code>.
239 * If <code>edits</code> is empty, calls super.
240 */
241 public String getRedoPresentationName() {
242 UndoableEdit last = lastEdit();
243 if (last != null) {
244 return last.getRedoPresentationName();
245 } else {
246 return super.getRedoPresentationName();
247 }
248 }
249
250 /**
251 * Returns a string that displays and identifies this
252 * object's properties.
253 *
254 * @return a String representation of this object
255 */
256 public String toString()
257 {
258 return super.toString()
259 + " inProgress: " + inProgress
260 + " edits: " + edits;
261 }
262 }