
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O'Reilly 
*/
// UndoableToggleApp3.java
//A sample app showing the use of UndoManager.
//

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;

public class Undo1 extends JFrame {

  private UndoManager manager = new UndoManager();

  private JButton undoButton;

  private JButton redoButton;

  // Create the main frame and everything in it.
  public Undo1() {

    // Create some toggle buttons.
    UndoableJToggleButton tog1 = new UndoableJToggleButton("One");
    UndoableJToggleButton tog2 = new UndoableJToggleButton("Two");
    UndoableJToggleButton tog3 = new UndoableJToggleButton("Three");

    // Add our listener to each toggle button.
    SimpleUEListener sl = new SimpleUEListener();
    tog1.addUndoableEditListener(sl);
    tog2.addUndoableEditListener(sl);
    tog3.addUndoableEditListener(sl);

    // Lay out the buttons.
    Box buttonBox = new Box(BoxLayout.Y_AXIS);
    buttonBox.add(tog1);
    buttonBox.add(tog2);
    buttonBox.add(tog3);

    // Create undo and redo buttons (initially disabled).
    undoButton = new JButton("Undo");
    redoButton = new JButton("Redo");
    undoButton.setEnabled(false);
    redoButton.setEnabled(false);

    // Add a listener to the undo button. It attempts to call undo() on the
    // UndoManager, then enables/disables the undo/redo buttons as
    // appropriate.
    undoButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ev) {
        try {
          manager.undo();
        } catch (CannotUndoException ex) {
          ex.printStackTrace();
        } finally {
          updateButtons();
        }
      }
    });

    // Add a redo listener: just like the undo listener.
    redoButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ev) {
        try {
          manager.redo();
        } catch (CannotRedoException ex) {
          ex.printStackTrace();
        } finally {
          updateButtons();
        }
      }
    });

    // Lay out the undo/redo buttons.
    Box undoRedoBox = new Box(BoxLayout.X_AXIS);
    undoRedoBox.add(Box.createGlue());
    undoRedoBox.add(undoButton);
    undoRedoBox.add(Box.createHorizontalStrut(2));
    undoRedoBox.add(redoButton);
    undoRedoBox.add(Box.createGlue());

    // Lay out the main frame.
    getContentPane().setLayout(new BorderLayout());
    getContentPane().add(buttonBox, BorderLayout.CENTER);
    getContentPane().add(undoRedoBox, BorderLayout.SOUTH);
    setSize(400, 150);
  }

  public class SimpleUEListener implements UndoableEditListener {
    // When an UndoableEditEvent is generated (each time one of the buttons
    // is pressed), we add it to the UndoManager and then get the manager's
    // undo/redo names and set the undo/redo button labels. Finally, we
    // enable/disable these buttons by asking the manager what we are
    // allowed to do.
    public void undoableEditHappened(UndoableEditEvent ev) {
      manager.addEdit(ev.getEdit());
      updateButtons();
    }
  }

  // Method to set the text and state of the undo/redo buttons.
  protected void updateButtons() {
    undoButton.setText(manager.getUndoPresentationName());
    redoButton.setText(manager.getRedoPresentationName());
    undoButton.getParent().validate();
    undoButton.setEnabled(manager.canUndo());
    redoButton.setEnabled(manager.canRedo());
  }

  // Main program just creates the frame and displays it.
  public static void main(String[] args) {
    JFrame f = new Undo1();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
  }
}

//UndoableJToggleButton.java
//Sample undoable toggle button class. Supports only a single listener to
//simplify the code.
//

class UndoableJToggleButton extends JToggleButton {
  private UndoableEditListener listener;

  // For this example, we'll just provide one constructor . . .
  public UndoableJToggleButton(String txt) {
    super(txt);
  }

  // Set the UndoableEditListener.
  public void addUndoableEditListener(UndoableEditListener l) {
    listener = l; // Should ideally throw an exception if listener != null
  }

  // Remove the UndoableEditListener.
  public void removeUndoableEditListener(UndoableEditListener l) {
    listener = null;
  }

  // We override this method to call the super implementation first (to fire
  // the
  // action event) and then fire a new UndoableEditEvent to our listener.
  protected void fireActionPerformed(ActionEvent ev) {

    // Fire the ActionEvent as usual.
    super.fireActionPerformed(ev);

    if (listener != null) {
      listener.undoableEditHappened(new UndoableEditEvent(this,
          new UndoableToggleEdit(this)));
    }
  }
}

//UndoableToggleEdit.java
//An UndoableEdit used to undo the pressing of a JToggleButton.
//

class UndoableToggleEdit extends AbstractUndoableEdit {

  private JToggleButton button;

  private boolean selected;

  // Create a new edit for a JToggleButton that has just been toggled.
  public UndoableToggleEdit(JToggleButton button) {
    this.button = button;
    selected = button.isSelected();
  }

  // Return a reasonable name for this edit.
  public String getPresentationName() {
    return "Toggle " + button.getText() + " " + (selected ? "on" : "off");
  }

  // Redo by setting the button state as it was initially.
  public void redo() throws CannotRedoException {
    super.redo();
    button.setSelected(selected);
  }

  // Undo by setting the button state to the opposite value.
  public void undo() throws CannotUndoException {
    super.undo();
    button.setSelected(!selected);
  }
}
