1 /* 2 * Copyright (c) 1997, 2004, 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 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 = 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 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 = 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 }