diff options
Diffstat (limited to 'libjava/classpath/javax/swing/undo/UndoableEditSupport.java')
-rw-r--r-- | libjava/classpath/javax/swing/undo/UndoableEditSupport.java | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/undo/UndoableEditSupport.java b/libjava/classpath/javax/swing/undo/UndoableEditSupport.java new file mode 100644 index 00000000000..918e7352313 --- /dev/null +++ b/libjava/classpath/javax/swing/undo/UndoableEditSupport.java @@ -0,0 +1,271 @@ +/* UndoableEditSupport.java -- + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.undo; + +import java.util.Iterator; +import java.util.Vector; + +import javax.swing.event.UndoableEditEvent; +import javax.swing.event.UndoableEditListener; + +/** + * A helper class for supporting {@link + * javax.swing.event.UndoableEditListener}. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class UndoableEditSupport +{ + /** + * The number of times that {@link #beginUpdate()} has been called + * without a matching call to {@link #endUpdate()}. + */ + protected int updateLevel; + + + /** + * compoundEdit + */ + protected CompoundEdit compoundEdit; + + + /** + * The currently registered listeners. + */ + protected Vector listeners = new Vector(); + + + /** + * The source of the broadcast UndoableEditEvents. + */ + protected Object realSource; + + + /** + * Constructs a new helper for broadcasting UndoableEditEvents. The + * events will indicate the newly constructed + * <code>UndoableEditSupport</code> instance as their source. + * + * @see #UndoableEditSupport(java.lang.Object) + */ + public UndoableEditSupport() + { + realSource = this; + } + + + /** + * Constructs a new helper for broadcasting UndoableEditEvents. + * + * @param realSource the source of the UndoableEditEvents that will + * be broadcast by this helper. If <code>realSource</code> is + * <code>null</code>, the events will indicate the newly constructed + * <code>UndoableEditSupport</code> instance as their source. + */ + public UndoableEditSupport(Object realSource) + { + if (realSource == null) + realSource = this; + this.realSource = realSource; + } + + + /** + * Returns a string representation of this object that may be useful + * for debugging. + */ + public String toString() + { + // Note that often, this.realSource == this. Therefore, dumping + // realSource without additional checks may lead to infinite + // recursion. See Classpath bug #7119. + return super.toString() + " updateLevel: " + updateLevel + + " listeners: " + listeners + " compoundEdit: " + compoundEdit; + } + + + /** + * Registers a listener. + * + * @param val the listener to be added. + */ + public synchronized void addUndoableEditListener(UndoableEditListener val) + { + listeners.add(val); + } + + + /** + * Unregisters a listener. + * @param val the listener to be removed. + */ + public synchronized void removeUndoableEditListener(UndoableEditListener val) + { + listeners.removeElement(val); + } + + + /** + * Returns an array containing the currently registered listeners. + */ + public synchronized UndoableEditListener[] getUndoableEditListeners() + { + UndoableEditListener[] result = new UndoableEditListener[listeners.size()]; + return (UndoableEditListener[]) listeners.toArray(result); + } + + + /** + * Notifies all registered listeners that an {@link + * UndoableEditEvent} has occured. + * + * <p><b>Lack of Thread Safety:</b> It is <em>not</em> safe to call + * this method from concurrent threads, unless the call is protected + * by a synchronization on this <code>UndoableEditSupport</code> + * instance. + * + * @param edit the edit action to be posted. + */ + protected void _postEdit(UndoableEdit edit) + { + UndoableEditEvent event; + Iterator iter; + + // Do nothing if we have no listeners. + if (listeners.isEmpty()) + return; + + event = new UndoableEditEvent(realSource, edit); + + // We clone the vector because this allows listeners to register + // or unregister listeners in their undoableEditHappened method. + // Otherwise, this would throw exceptions (in the case of + // Iterator, a java.util.ConcurrentModificationException; in the + // case of a direct loop over the Vector elements, some + // index-out-of-bounds exception). + iter = ((Vector) listeners.clone()).iterator(); + while (iter.hasNext()) + ((UndoableEditListener) iter.next()).undoableEditHappened(event); + } + + + /** + * If {@link #beginUpdate} has been called (so that the current + * update level is greater than zero), adds the specified edit + * to {@link #compoundEdit}. Otherwise, notify listeners of the + * edit by calling {@link #_postEdit(UndoableEdit)}. + * + * <p><b>Thread Safety:</b> It is safe to call this method from any + * thread without external synchronization. + * + * @param edit the edit action to be posted. + */ + public synchronized void postEdit(UndoableEdit edit) + { + if (compoundEdit != null) + compoundEdit.addEdit(edit); + else + _postEdit(edit); + } + + + /** + * Returns the current update level. + */ + public int getUpdateLevel() + { + return updateLevel; + } + + + /** + * Starts a (possibly nested) update session. If the current update + * level is zero, {@link #compoundEdit} is set to the result of the + * {@link #createCompoundEdit} method. In any case, the update level + * is increased by one. + * + * <p><b>Thread Safety:</b> It is safe to call this method from any + * thread without external synchronization. + */ + public synchronized void beginUpdate() + { + if (compoundEdit == null) + compoundEdit = createCompoundEdit(); + ++updateLevel; + } + + + /** + * Creates a new instance of {@link CompoundEdit}. Called by {@link + * #beginUpdate}. If a subclass wants {@link #beginUpdate} to work + * on a specific {@link #compoundEdit}, it should override this + * method. + * + * @returns a newly created instance of {@link CompoundEdit}. + */ + protected CompoundEdit createCompoundEdit() + { + return new CompoundEdit(); + } + + + /** + * Ends an update session. If the terminated session was the + * outermost session, {@link #compoundEdit} will receive an + * <code>end</code> message, and {@link #_postEdit} gets called in + * order to notify any listeners. Finally, the + * <code>compoundEdit</code> is discarded. + * + * <p><b>Thread Safety:</b> It is safe to call this method from any + * thread without external synchronization. + */ + public synchronized void endUpdate() + { + if (updateLevel == 0) + throw new IllegalStateException(); + + if (--updateLevel > 0) + return; + + compoundEdit.end(); + _postEdit(compoundEdit); + compoundEdit = null; + } +} |