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