//package undo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.undo.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
/**
* The lunch applet presents the Lunch button, which, when invoked
* launches the main frame
*
*[url]http://www.javaworld.com/javaworld/jw-06-1998/jw-06-undoredo.html[/url]
*/
public class LunchApplet extends JApplet {
//Initialize the applet
public void init() {
// set look & feel
String laf = UIManager.getSystemLookAndFeelClassName();
try {
UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
} catch ( UnsupportedLookAndFeelException exc ) {
System.err.println("Warning: UnsupportedLookAndFeel: " + laf);
} catch (Exception exc) {
System.err.println("Error loading " + laf + ": " + exc);
}
JButton lunchBtn = new JButton("Lunch");
lunchBtn.addActionListener( new ActionListener () {
public void actionPerformed( ActionEvent evt ) {
UndoPanel app = new UndoPanel();
JFrame frame = new JFrame();
frame.getContentPane().add(app);
frame.setSize(600,300);
frame.setVisible(true);
}});
getContentPane().add(lunchBtn);
}
//Start the applet
public void start() {
}
//Stop the applet
public void stop() {
}
//Destroy the applet
public void destroy() {
}
}
/**
* The Add Edit class records the changes which occured to the
* list after performing an add action. The add edit supports
* undo / redo of add action.
*/
class AddEdit extends AbstractUndoableEdit {
private Object element_;
private int index_;
private DefaultListModel model_;
public AddEdit( DefaultListModel model, Object element, int index ) {
model_=model;
element_ = element;
index_=index;
}
public void undo() throws CannotUndoException {
model_.removeElementAt( index_ );
}
public void redo() throws CannotRedoException {
model_.insertElementAt( element_, index_ );
}
public boolean canUndo() {
return true;
}
public boolean canRedo() {
return true;
}
public String getPresentationName() {
return "Add";
}
}
/**
* Same as AddEdit. The RemoveEdit records changes which
* occured after performing a remove action
*/
class RemoveEdit extends AbstractUndoableEdit {
private Object element_;
private int index_;
private DefaultListModel model_;
public RemoveEdit ( DefaultListModel model,Object element, int index ) {
model_ = model;
element_ = element;
index_=index;
}
public void undo() throws CannotUndoException {
model_.insertElementAt( element_, index_);
}
public void redo() throws CannotRedoException {
model_.removeElementAt( index_);
}
public boolean canUndo() {
return true;
}
public boolean canRedo() {
return true;
}
public String getPresentationName() {
return "Remove";
}
}
/**
* The undo applet defines the undo / redo concept
* in swing. The applet allows you to add / remove
* objects to/from a list. It also supports undoing/
* redoing those operations
*/
class UndoPanel extends JPanel {
JList elementList_; // The list
DefaultListModel elementModel_; // The list model
JScrollPane scrollPane_;
JButton addElementBtn_ ;
JButton removeElementBtn_ ;
JButton undoBtn_;
JButton redoBtn_;
int _lastElementID;
/**
* undo system elements
*/
UndoManager undoManager_; // history list
UndoableEditSupport undoSupport_; // event support
public UndoPanel() {
elementModel_ = new DefaultListModel();
elementList_ = new JList(elementModel_);
scrollPane_ = new JScrollPane(elementList_);
elementList_.addListSelectionListener(new ListSelectionAdapter());
// create the actions
Action addAction = new AddAction();
Action removeAction = new RemoveAction();
Action undoAction = new UndoAction();
Action redoAction = new RedoAction();
// create the buttons and register the actions
addElementBtn_ = new JButton("Add Foo");
addElementBtn_.addActionListener(addAction);
removeElementBtn_ = new JButton("remove Foo");
removeElementBtn_.addActionListener(removeAction);
removeElementBtn_.setEnabled(false);
undoBtn_ = new JButton("undo");
undoBtn_.addActionListener(undoAction);
redoBtn_ = new JButton("redo");
redoBtn_.addActionListener(redoAction);
// create the undo / redo panel
JPanel undoPanel = new JPanel();
undoPanel.setLayout(new GridLayout(1,2));
undoPanel.setBorder(
BorderFactory.createTitledBorder(
LineBorder.createBlackLineBorder(),
"Undo/ Redo",
TitledBorder.LEFT,
TitledBorder.TOP));
undoPanel.add(undoBtn_);
undoPanel.add(redoBtn_);
// create the actions panel
JPanel actionPanel = new JPanel();
actionPanel.setLayout(new GridLayout(1,2));
actionPanel.setBorder(
BorderFactory.createTitledBorder(
LineBorder.createBlackLineBorder(),
"Actions",
TitledBorder.LEFT,
TitledBorder.TOP));
actionPanel.add(addElementBtn_);
actionPanel.add(removeElementBtn_);
// create the task panel
JPanel taskPanel= new JPanel();
taskPanel.setLayout(new GridLayout(1,2));
taskPanel.add(actionPanel);
taskPanel.add(undoPanel);
taskPanel.setSize(100,100);
// add the task panel to the content pane
setLayout(new BorderLayout());
add(BorderLayout.SOUTH,taskPanel);
add(BorderLayout.CENTER,scrollPane_);
// initilize the undo.redo system
undoManager_= new UndoManager();
undoSupport_ = new UndoableEditSupport();
undoSupport_.addUndoableEditListener(new UndoAdapter());
refreshUndoRedo();
}
/**
* This method is called after each undoable operation
* in order to refresh the presentation state of the
* undo/redo GUI
*/
public void refreshUndoRedo() {
// refresh undo
undoBtn_.setText( undoManager_.getUndoPresentationName() );
undoBtn_.setEnabled( undoManager_.canUndo() );
// refresh redo
redoBtn_.setText( undoManager_.getRedoPresentationName() );
redoBtn_.setEnabled( undoManager_.canRedo() );
}
/**
* Add new element Action.
*/
private class AddAction extends AbstractAction {
public void actionPerformed(ActionEvent evt) {
// always add to the end of the JList
int NumOfElements = elementModel_.getSize();
// however, give the the element is ID number
Object element = new String("Foo " + _lastElementID);
// record the effect
UndoableEdit edit = new AddEdit(elementModel_,
element, NumOfElements );
// perform the operation
elementModel_.addElement( element );
// notify the listeners
undoSupport_.postEdit( edit );
// increment the ID
_lastElementID ++ ;
}
}
/**
* The remove action
*/
private class RemoveAction extends AbstractAction {
public void actionPerformed( ActionEvent evt ) {
int selectIdx = elementList_.getSelectedIndex();
Object selectedElement = elementModel_.getElementAt( selectIdx );
// create the edit
UndoableEdit edit_ = new RemoveEdit( elementModel_,
selectedElement, selectIdx );
//perfrom the remove
elementModel_.removeElementAt( selectIdx );
// notify the listeners
undoSupport_.postEdit( edit_ );
//disable the remove button
removeElementBtn_.setEnabled( false );
}
}
/**
* undo action
*/
private class UndoAction extends AbstractAction {
public void actionPerformed( ActionEvent evt ) {
undoManager_.undo();
refreshUndoRedo();
}
}
/**
* inner class that defines the redo action
*/
private class RedoAction extends AbstractAction {
public void actionPerformed(ActionEvent evt ) {
undoManager_.redo();
refreshUndoRedo();
}
}
/**
* An undo/redo adpater. The adpater is notified when
* an undo edit occur(e.g. add or remove from the list)
* The adptor extract the edit from the event, add it
* to the UndoManager, and refresh the GUI
*/
private class UndoAdapter implements UndoableEditListener {
public void undoableEditHappened (UndoableEditEvent evt) {
UndoableEdit edit = evt.getEdit();
undoManager_.addEdit( edit );
refreshUndoRedo();
}
}
/**
* The list selection adpater change the remove button state
* according to the selection of the list
*/
private class ListSelectionAdapter implements ListSelectionListener {
public void valueChanged (ListSelectionEvent evt) {
if ( evt.getLastIndex() >= evt.getFirstIndex()) {
removeElementBtn_.setEnabled(true);
}
}
}
}