1 /* 2 * Copyright (c) 1997, 2015, 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 26 package javax.swing.undo; 27 28 import javax.swing.event.*; 29 import java.util.*; 30 31 /** 32 * A support class used for managing {@code UndoableEdit} listeners. 33 * 34 * @author Ray Ryan 35 */ 36 public class UndoableEditSupport { 37 /** 38 * The update level. 39 */ 40 protected int updateLevel; 41 /** 42 * The compound edit. 43 */ 44 protected CompoundEdit compoundEdit; 45 /** 46 * The list of listeners. 47 */ 48 protected Vector<UndoableEditListener> listeners; 49 /** 50 * The real source. 51 */ 52 protected Object realSource; 53 54 /** 55 * Constructs an {@code UndoableEditSupport} object. 56 */ 57 public UndoableEditSupport() { 58 this(null); 59 } 60 61 /** 62 * Constructs an {@code UndoableEditSupport} object. 63 * 64 * @param r an {@code Object} 65 */ 66 public UndoableEditSupport(Object r) { 67 realSource = r == null ? this : r; 68 updateLevel = 0; 69 compoundEdit = null; 70 listeners = new Vector<UndoableEditListener>(); 71 } 72 73 /** 74 * Registers an {@code UndoableEditListener}. 75 * The listener is notified whenever an edit occurs which can be undone. 76 * 77 * @param l an {@code UndoableEditListener} object 78 * @see #removeUndoableEditListener 79 */ 80 public synchronized void addUndoableEditListener(UndoableEditListener l) { 81 listeners.addElement(l); 82 } 83 84 /** 85 * Removes an {@code UndoableEditListener}. 86 * 87 * @param l the {@code UndoableEditListener} object to be removed 88 * @see #addUndoableEditListener 89 */ 90 public synchronized void removeUndoableEditListener(UndoableEditListener l) 91 { 92 listeners.removeElement(l); 93 } 94 95 /** 96 * Returns an array of all the {@code UndoableEditListener}s added 97 * to this UndoableEditSupport with addUndoableEditListener(). 98 * 99 * @return all of the {@code UndoableEditListener}s added or an empty 100 * array if no listeners have been added 101 * @since 1.4 102 */ 103 public synchronized UndoableEditListener[] getUndoableEditListeners() { 104 return listeners.toArray(new UndoableEditListener[0]); 105 } 106 107 /** 108 * Called only from {@code postEdit} and {@code endUpdate}. Calls 109 * {@code undoableEditHappened} in all listeners. No synchronization 110 * is performed here, since the two calling methods are synchronized. 111 * 112 * @param e edit to be verified 113 */ 114 protected void _postEdit(UndoableEdit e) { 115 UndoableEditEvent ev = new UndoableEditEvent(realSource, e); 116 @SuppressWarnings("unchecked") 117 Enumeration<UndoableEditListener> cursor = 118 ((Vector<UndoableEditListener>)listeners.clone()).elements(); 119 while (cursor.hasMoreElements()) { 120 cursor.nextElement().undoableEditHappened(ev); 121 } 122 } 123 124 /** 125 * DEADLOCK WARNING: Calling this method may call 126 * {@code undoableEditHappened} in all listeners. 127 * It is unwise to call this method from one of its listeners. 128 * 129 * @param e edit to be posted 130 */ 131 public synchronized void postEdit(UndoableEdit e) { 132 if (updateLevel == 0) { 133 _postEdit(e); 134 } else { 135 // PENDING(rjrjr) Throw an exception if this fails? 136 compoundEdit.addEdit(e); 137 } 138 } 139 140 /** 141 * Returns the update level value. 142 * 143 * @return an integer representing the update level 144 */ 145 public int getUpdateLevel() { 146 return updateLevel; 147 } 148 149 /** 150 * 151 */ 152 public synchronized void beginUpdate() { 153 if (updateLevel == 0) { 154 compoundEdit = createCompoundEdit(); 155 } 156 updateLevel++; 157 } 158 159 /** 160 * Called only from {@code beginUpdate}. 161 * Exposed here for subclasses' use. 162 * 163 * @return new created {@code CompoundEdit} object 164 */ 165 protected CompoundEdit createCompoundEdit() { 166 return new CompoundEdit(); 167 } 168 169 /** 170 * DEADLOCK WARNING: Calling this method may call 171 * {@code undoableEditHappened} in all listeners. 172 * It is unwise to call this method from one of its listeners. 173 */ 174 public synchronized void endUpdate() { 175 updateLevel--; 176 if (updateLevel == 0) { 177 compoundEdit.end(); 178 _postEdit(compoundEdit); 179 compoundEdit = null; 180 } 181 } 182 183 /** 184 * Returns a string that displays and identifies this 185 * object's properties. 186 * 187 * @return a {@code String} representation of this object 188 */ 189 public String toString() { 190 return super.toString() + 191 " updateLevel: " + updateLevel + 192 " listeners: " + listeners + 193 " compoundEdit: " + compoundEdit; 194 } 195 }