/*
* 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);
}
}