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