/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * ExtendedUndoManager.java * Creation date: (03/27/2002 5:54:00 PM) * By: Edward Lam */ package org.openquark.gems.client.utilities; import java.util.ArrayList; import java.util.List; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; import javax.swing.undo.UndoManager; import javax.swing.undo.UndoableEdit; import javax.swing.undo.UndoableEditSupport; /** * An extension of UndoManager that provides two additional features: * 1. The ability to add and remove listeners * 2. The ability to gain more extensive access to the edits being managed. * It will also ignore any "new" undo edit that is generated by actually undoing/redoing something * (to avoid double-counting). * See: O'Reilly's Java Swing (1st edition) * Creation date: (03/27/2002 5:54:00 PM) * @author Edward Lam */ public class ExtendedUndoManager extends UndoManager implements UndoableEditListener { private static final long serialVersionUID = 4293111947852472479L; /** Support class that helps us to manage listeners. */ private ExtendedUndoableEditSupport support = new ExtendedUndoableEditSupport(); /** The source of the last edit */ private Object source; /** The thread currently undoing/redoing, if any.*/ private Thread undoingOrRedoingThread = null; /** * A simple extension of UndoableEditSupport that lets us specify the event source each time * we post an edit. * Creation date: (03/27/2002 6:09:00 PM) */ class ExtendedUndoableEditSupport extends UndoableEditSupport { /** * Post an edit to added listeners. * Creation date: (03/27/2002 6:10:00 PM) * @param ue UndoableEdit the edit to post */ public synchronized void postEdit(UndoableEdit ue) { realSource = source; // from the enclosing manager object super.postEdit(ue); } } /** * Redo * Creation date: (03/28/2002 5:45:00 PM) */ public void redo() { undoingOrRedoingThread = Thread.currentThread(); super.redo(); undoingOrRedoingThread = null; } /** * Undo * Creation date: (03/28/2002 5:47:00 PM) */ public void undo() { undoingOrRedoingThread = Thread.currentThread(); super.undo(); undoingOrRedoingThread = null; } /* * Methods for access to edits ************************************************************ */ /** * {@inheritDoc} */ public UndoableEdit editToBeUndone() { return super.editToBeUndone(); } /** * {@inheritDoc} */ public UndoableEdit editToBeRedone() { return super.editToBeRedone(); } /** * Return the complete list of edits in an array. * Creation date: (03/27/2002 5:56:00 PM) * @return UndoableEdit[] the complete list of edits. */ public synchronized UndoableEdit[] getEdits() { UndoableEdit[] array = new UndoableEdit[edits.size()]; edits.copyInto(array); return array; } /** * Return all currently significant undoable edits. * The first edit will be the next one to be undone. * Creation date: (03/27/2002 5:58:00 PM) * @return UndoableEdit[] the currently significant undoable edits. */ public synchronized UndoableEdit[] getUndoableEdits() { int nEdits = edits.size(); List<UndoableEdit> undoableEditList = new ArrayList<UndoableEdit>(nEdits); for (int i = nEdits - 1; i >= 0; i--) { UndoableEdit u = edits.elementAt(i); if (u.canUndo() && u.isSignificant()) { undoableEditList.add(u); } } return undoableEditList.toArray(new UndoableEdit[undoableEditList.size()]); } /** * Return all currently significant redoable edits. * The first edit will be the next one to be redone. * Creation date: (03/27/2002 6:01:00 PM) * @return UndoableEdit[] the currently significant redoable edits. */ public synchronized UndoableEdit[] getRedoableEdits() { int nEdits = edits.size(); List<UndoableEdit> redoableEditList = new ArrayList<UndoableEdit>(nEdits); for (int i = 0; i < nEdits; i++) { UndoableEdit u = edits.elementAt(i); if (u.canRedo() && u.isSignificant()) { redoableEditList.add(u); } } return redoableEditList.toArray(new UndoableEdit[redoableEditList.size()]); } /* * UndoableEditListener Method Support ************************************************************ */ /** * Add an edit and notify our listeners. * Creation date: (03/27/2002 6:03:00 PM) * @param anEdit UndoableEdit the edit to add. * @return boolean whether the edit was indeed added. */ public synchronized boolean addEdit(UndoableEdit anEdit) { // ignore if this edit is generated by an undo/redo action // TODOEL: get rid of this. We can't though, until we can figure out if VEP value changes // come from edits or just programatically setting the value. if (Thread.currentThread() == undoingOrRedoingThread) { return false; } boolean b = super.addEdit(anEdit); // if the edit was added, notify listeners if (b) { support.postEdit(anEdit); } return b; } /** * When an edit is sent to us, call addEdit() to notify any of our listeners. * Creation date: (03/27/2002 6:04:00 PM) * @param ev UndoableEditEvent the edit event which happened. */ public synchronized void undoableEditHappened(UndoableEditEvent ev) { UndoableEdit ue = ev.getEdit(); source = ev.getSource(); addEdit(ue); } /** * Add a listener to be notified each time an edit is added to this manager. * This makes it easy to update undo/redo menus as edits are added. * Creation date: (03/27/2002 6:06:00 PM) * @param l UndoableEditListener the listener to add. */ public synchronized void addUndoableEditListener(UndoableEditListener l) { support.addUndoableEditListener(l); } /** * Remove a listener from this manager. * Creation date: (03/27/2002 6:07:00 PM) * @param l UndoableEditListener the listener to remove. */ public synchronized void removeUndoableEditListener(UndoableEditListener l) { support.removeUndoableEditListener(l); } }