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