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