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