GNU Classpath (0.20) | |
Frames | No Frames |
1: /* UndoableEditSupport.java -- 2: Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.undo; 40: 41: import java.util.Iterator; 42: import java.util.Vector; 43: 44: import javax.swing.event.UndoableEditEvent; 45: import javax.swing.event.UndoableEditListener; 46: 47: /** 48: * A helper class for supporting {@link 49: * javax.swing.event.UndoableEditListener}. 50: * 51: * @author Andrew Selkirk (aselkirk@sympatico.ca) 52: * @author Sascha Brawer (brawer@dandelis.ch) 53: */ 54: public class UndoableEditSupport 55: { 56: /** 57: * The number of times that {@link #beginUpdate()} has been called 58: * without a matching call to {@link #endUpdate()}. 59: */ 60: protected int updateLevel; 61: 62: 63: /** 64: * compoundEdit 65: */ 66: protected CompoundEdit compoundEdit; 67: 68: 69: /** 70: * The currently registered listeners. 71: */ 72: protected Vector listeners = new Vector(); 73: 74: 75: /** 76: * The source of the broadcast UndoableEditEvents. 77: */ 78: protected Object realSource; 79: 80: 81: /** 82: * Constructs a new helper for broadcasting UndoableEditEvents. The 83: * events will indicate the newly constructed 84: * <code>UndoableEditSupport</code> instance as their source. 85: * 86: * @see #UndoableEditSupport(java.lang.Object) 87: */ 88: public UndoableEditSupport() 89: { 90: realSource = this; 91: } 92: 93: 94: /** 95: * Constructs a new helper for broadcasting UndoableEditEvents. 96: * 97: * @param realSource the source of the UndoableEditEvents that will 98: * be broadcast by this helper. If <code>realSource</code> is 99: * <code>null</code>, the events will indicate the newly constructed 100: * <code>UndoableEditSupport</code> instance as their source. 101: */ 102: public UndoableEditSupport(Object realSource) 103: { 104: if (realSource == null) 105: realSource = this; 106: this.realSource = realSource; 107: } 108: 109: 110: /** 111: * Returns a string representation of this object that may be useful 112: * for debugging. 113: */ 114: public String toString() 115: { 116: // Note that often, this.realSource == this. Therefore, dumping 117: // realSource without additional checks may lead to infinite 118: // recursion. See Classpath bug #7119. 119: return super.toString() + " updateLevel: " + updateLevel 120: + " listeners: " + listeners + " compoundEdit: " + compoundEdit; 121: } 122: 123: 124: /** 125: * Registers a listener. 126: * 127: * @param val the listener to be added. 128: */ 129: public synchronized void addUndoableEditListener(UndoableEditListener val) 130: { 131: listeners.add(val); 132: } 133: 134: 135: /** 136: * Unregisters a listener. 137: * @param val the listener to be removed. 138: */ 139: public synchronized void removeUndoableEditListener(UndoableEditListener val) 140: { 141: listeners.removeElement(val); 142: } 143: 144: 145: /** 146: * Returns an array containing the currently registered listeners. 147: */ 148: public synchronized UndoableEditListener[] getUndoableEditListeners() 149: { 150: UndoableEditListener[] result = new UndoableEditListener[listeners.size()]; 151: return (UndoableEditListener[]) listeners.toArray(result); 152: } 153: 154: 155: /** 156: * Notifies all registered listeners that an {@link 157: * UndoableEditEvent} has occured. 158: * 159: * <p><b>Lack of Thread Safety:</b> It is <em>not</em> safe to call 160: * this method from concurrent threads, unless the call is protected 161: * by a synchronization on this <code>UndoableEditSupport</code> 162: * instance. 163: * 164: * @param edit the edit action to be posted. 165: */ 166: protected void _postEdit(UndoableEdit edit) 167: { 168: UndoableEditEvent event; 169: Iterator iter; 170: 171: // Do nothing if we have no listeners. 172: if (listeners.isEmpty()) 173: return; 174: 175: event = new UndoableEditEvent(realSource, edit); 176: 177: // We clone the vector because this allows listeners to register 178: // or unregister listeners in their undoableEditHappened method. 179: // Otherwise, this would throw exceptions (in the case of 180: // Iterator, a java.util.ConcurrentModificationException; in the 181: // case of a direct loop over the Vector elements, some 182: // index-out-of-bounds exception). 183: iter = ((Vector) listeners.clone()).iterator(); 184: while (iter.hasNext()) 185: ((UndoableEditListener) iter.next()).undoableEditHappened(event); 186: } 187: 188: 189: /** 190: * If {@link #beginUpdate} has been called (so that the current 191: * update level is greater than zero), adds the specified edit 192: * to {@link #compoundEdit}. Otherwise, notify listeners of the 193: * edit by calling {@link #_postEdit(UndoableEdit)}. 194: * 195: * <p><b>Thread Safety:</b> It is safe to call this method from any 196: * thread without external synchronization. 197: * 198: * @param edit the edit action to be posted. 199: */ 200: public synchronized void postEdit(UndoableEdit edit) 201: { 202: if (compoundEdit != null) 203: compoundEdit.addEdit(edit); 204: else 205: _postEdit(edit); 206: } 207: 208: 209: /** 210: * Returns the current update level. 211: */ 212: public int getUpdateLevel() 213: { 214: return updateLevel; 215: } 216: 217: 218: /** 219: * Starts a (possibly nested) update session. If the current update 220: * level is zero, {@link #compoundEdit} is set to the result of the 221: * {@link #createCompoundEdit} method. In any case, the update level 222: * is increased by one. 223: * 224: * <p><b>Thread Safety:</b> It is safe to call this method from any 225: * thread without external synchronization. 226: */ 227: public synchronized void beginUpdate() 228: { 229: if (compoundEdit == null) 230: compoundEdit = createCompoundEdit(); 231: ++updateLevel; 232: } 233: 234: 235: /** 236: * Creates a new instance of {@link CompoundEdit}. Called by {@link 237: * #beginUpdate}. If a subclass wants {@link #beginUpdate} to work 238: * on a specific {@link #compoundEdit}, it should override this 239: * method. 240: * 241: * @returns a newly created instance of {@link CompoundEdit}. 242: */ 243: protected CompoundEdit createCompoundEdit() 244: { 245: return new CompoundEdit(); 246: } 247: 248: 249: /** 250: * Ends an update session. If the terminated session was the 251: * outermost session, {@link #compoundEdit} will receive an 252: * <code>end</code> message, and {@link #_postEdit} gets called in 253: * order to notify any listeners. Finally, the 254: * <code>compoundEdit</code> is discarded. 255: * 256: * <p><b>Thread Safety:</b> It is safe to call this method from any 257: * thread without external synchronization. 258: */ 259: public synchronized void endUpdate() 260: { 261: if (updateLevel == 0) 262: throw new IllegalStateException(); 263: 264: if (--updateLevel > 0) 265: return; 266: 267: compoundEdit.end(); 268: _postEdit(compoundEdit); 269: compoundEdit = null; 270: } 271: }
GNU Classpath (0.20) |