Swing JFC Java

/*
Core SWING Advanced Programming 
By Kim Topley
ISBN: 0 13 083292 8       
Publisher: Prentice Hall  
*/
import java.awt.BorderLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Hashtable;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.EventListenerList;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEdit;
public class UndoExample5 extends JFrame {
  public UndoExample5() {
    super("Undo/Redo Example 5");
    pane = new JTextPane();
    pane.setEditable(true); // Editable
    getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER);
    // Add a menu bar
    menuBar = new JMenuBar();
    setJMenuBar(menuBar);
    // Populate the menu bar
    createMenuBar();
    // Create the undo manager and actions
    MonitorableUndoManager manager = new MonitorableUndoManager();
    pane.getDocument().addUndoableEditListener(manager);
    Action undoAction = new UndoAction(manager);
    Action redoAction = new RedoAction(manager);
    // Add the actions to buttons
    JPanel panel = new JPanel();
    final JButton undoButton = new JButton("Undo");
    final JButton redoButton = new JButton("Redo");
    undoButton.addActionListener(undoAction);
    redoButton.addActionListener(redoAction);
    undoButton.setEnabled(false);
    redoButton.setEnabled(false);
    panel.add(undoButton);
    panel.add(redoButton);
    getContentPane().add(panel, BorderLayout.SOUTH);
    // Assign the actions to keys
    pane.registerKeyboardAction(undoAction, KeyStroke.getKeyStroke(
        KeyEvent.VK_Z, InputEvent.CTRL_MASK), JComponent.WHEN_FOCUSED);
    pane.registerKeyboardAction(redoAction, KeyStroke.getKeyStroke(
        KeyEvent.VK_Y, InputEvent.CTRL_MASK), JComponent.WHEN_FOCUSED);
    // Handle events from the MonitorableUndoManager
    manager.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent evt) {
        MonitorableUndoManager m = (MonitorableUndoManager) evt
            .getSource();
        boolean canUndo = m.canUndo();
        boolean canRedo = m.canRedo();
        undoButton.setEnabled(canUndo);
        redoButton.setEnabled(canRedo);
        undoButton.setToolTipText(canUndo ? m.getUndoPresentationName()
            : null);
        redoButton.setToolTipText(canRedo ? m.getRedoPresentationName()
            : null);
      }
    });
  }
  public void createMenuBar() {
    // Remove the existing menu items
    int count = menuBar.getMenuCount();
    for (int i = 0; i < count; i++) {
      menuBar.remove(menuBar.getMenu(0));
    }
    // Build the new menu.
    Action[] actions = pane.getActions();
    Hashtable actionHash = new Hashtable();
    count = actions.length;
    for (int i = 0; i < count; i++) {
      actionHash.put(actions[i].getValue(Action.NAME), actions[i]);
    }
    // Add the font menu
    JMenu menu = MenuBuilder.buildMenu("Font", fontSpec, actionHash);
    if (menu != null) {
      menuBar.add(menu);
    }
    // Add the alignment menu
    menu = MenuBuilder.buildMenu("Align", alignSpec, actionHash);
    if (menu != null) {
      menuBar.add(menu);
    }
  }
  // The Undo action
  public class UndoAction extends AbstractAction {
    public UndoAction(UndoManager manager) {
      this.manager = manager;
    }
    public void actionPerformed(ActionEvent evt) {
      try {
        manager.undo();
      } catch (CannotUndoException e) {
        Toolkit.getDefaultToolkit().beep();
      }
    }
    private UndoManager manager;
  }
  // The Redo action
  public class RedoAction extends AbstractAction {
    public RedoAction(UndoManager manager) {
      this.manager = manager;
    }
    public void actionPerformed(ActionEvent evt) {
      try {
        manager.redo();
      } catch (CannotRedoException e) {
        Toolkit.getDefaultToolkit().beep();
      }
    }
    private UndoManager manager;
  }
  public static void main(String[] args) {
    try {
        UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
    } catch (Exception evt) {}
  
    JFrame f = new UndoExample5();
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent evt) {
        System.exit(0);
      }
    });
    f.setSize(250, 300);
    f.setVisible(true);
    // Create and show a frame monitoring undoable edits
    JFrame undoMonitor = new JFrame("Undo Monitor");
    final JTextArea textArea = new JTextArea();
    textArea.setEditable(false);
    undoMonitor.getContentPane().add(new JScrollPane(textArea));
    undoMonitor.setBounds(f.getLocation().x + f.getSize().width, f
        .getLocation().y, 400, 200);
    undoMonitor.setVisible(true);
    pane.getDocument().addUndoableEditListener(new UndoableEditListener() {
      public void undoableEditHappened(UndoableEditEvent evt) {
        UndoableEdit edit = evt.getEdit();
        textArea.append(edit.getPresentationName() + "("
            + edit.toString() + ")\n");
      }
    });
    // Create and show a frame monitoring document edits
    JFrame editMonitor = new JFrame("Edit Monitor");
    final JTextArea textArea2 = new JTextArea();
    textArea2.setEditable(false);
    editMonitor.getContentPane().add(new JScrollPane(textArea2));
    editMonitor.setBounds(undoMonitor.getLocation().x, undoMonitor
        .getLocation().y
        + undoMonitor.getSize().height, 400, 200);
    editMonitor.setVisible(true);
    pane.getDocument().addDocumentListener(new DocumentListener() {
      public void changedUpdate(DocumentEvent evt) {
        textArea2.append("Attribute change\n");
      }
      public void insertUpdate(DocumentEvent evt) {
        textArea2.append("Text insertion\n");
      }
      public void removeUpdate(DocumentEvent evt) {
        textArea2.append("Text removal\n");
      }
    });
  }
  private static JTextPane pane;
  private static JMenuBar menuBar;
  private static MenuSpec[] sizeSpec = new MenuSpec[] {
      new MenuSpec("Size 8", "font-size-8"),
      new MenuSpec("Size 10", "font-size-10"),
      new MenuSpec("Size 12", "font-size-12"),
      new MenuSpec("Size 14", "font-size-14"),
      new MenuSpec("Size 16", "font-size-16"),
      new MenuSpec("Size 18", "font-size-18"),
      new MenuSpec("Size 24", "font-size-24"),
      new MenuSpec("Size 36", "font-size-36"),
      new MenuSpec("Size 48", "font-size-48") };
  private static MenuSpec[] familySpec = new MenuSpec[] {
      new MenuSpec("Sans Serif", "font-family-SansSerif"),
      new MenuSpec("Monospaced", "font-family-Monospaced"),
      new MenuSpec("Serif", "font-family-Serif") };
  private static MenuSpec[] styleSpec = new MenuSpec[] {
      new MenuSpec("Bold", "font-bold"),
      new MenuSpec("Italics", "font-italic"),
      new MenuSpec("Underline", "font-underline") };
  // Menu definitions for fonts
  private static MenuSpec[] fontSpec = new MenuSpec[] {
      new MenuSpec("Size", sizeSpec), new MenuSpec("Family", familySpec),
      new MenuSpec("Style", styleSpec) };
  // Alignment
  private static MenuSpec[] alignSpec = new MenuSpec[] {
      new MenuSpec("Left", "left-justify"),
      new MenuSpec("Center", "center-justify"),
      new MenuSpec("Right", "right-justify") };
}
class MonitorableUndoManager extends UndoManager {
  // List of listeners for events from this object
  protected EventListenerList listenerList = new EventListenerList();
  // A ChangeEvent dedicated to a single MonitorableUndoManager
  protected ChangeEvent changeEvent;
  // Super class overrides
  public synchronized void setLimit(int l) {
    super.setLimit(l);
    fireChangeEvent();
  }
  public synchronized void discardAllEdits() {
    super.discardAllEdits();
    fireChangeEvent();
  }
  public synchronized void undo() throws CannotUndoException {
    super.undo();
    fireChangeEvent();
  }
  public synchronized void redo() throws CannotRedoException {
    super.redo();
    fireChangeEvent();
  }
  public synchronized boolean addEdit(UndoableEdit anEdit) {
    boolean retval = super.addEdit(anEdit);
    fireChangeEvent();
    return retval;
  }
  // Support for ChangeListeners
  public void addChangeListener(ChangeListener l) {
    listenerList.add(ChangeListener.class, l);
  }
  public void removeChangeListener(ChangeListener l) {
    listenerList.remove(ChangeListener.class, l);
  }
  protected void fireChangeEvent() {
    Object[] listeners = listenerList.getListenerList();
    for (int i = listeners.length - 2; i >= 0; i -= 2) {
      if (listeners[i] == ChangeListener.class) {
        if (changeEvent == null) {
          changeEvent = new ChangeEvent(this);
        }
        ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent);
      }
    }
  }
}
class MenuSpec {
  public MenuSpec(String name, MenuSpec[] subMenus) {
    this.name = name;
    this.subMenus = subMenus;
  }
  public MenuSpec(String name, String actionName) {
    this.name = name;
    this.actionName = actionName;
  }
  public MenuSpec(String name, Action action) {
    this.name = name;
    this.action = action;
  }
  public boolean isSubMenu() {
    return subMenus != null;
  }
  public boolean isAction() {
    return action != null;
  }
  public String getName() {
    return name;
  }
  public MenuSpec[] getSubMenus() {
    return subMenus;
  }
  public String getActionName() {
    return actionName;
  }
  public Action getAction() {
    return action;
  }
  private String name;
  private String actionName;
  private Action action;
  private MenuSpec[] subMenus;
}
class MenuBuilder {
  public static JMenu buildMenu(String name, MenuSpec[] menuSpecs,
      Hashtable actions) {
    int count = menuSpecs.length;
    JMenu menu = new JMenu(name);
    for (int i = 0; i < count; i++) {
      MenuSpec spec = menuSpecs[i];
      if (spec.isSubMenu()) {
        // Recurse to handle a sub menu
        JMenu subMenu = buildMenu(spec.getName(), spec.getSubMenus(),
            actions);
        if (subMenu != null) {
          menu.add(subMenu);
        }
      } else if (spec.isAction()) {
        // It's an Action - add it directly to the menu
        menu.add(spec.getAction());
      } else {
        // It's an action name - add it if possible
        String actionName = spec.getActionName();
        Action targetAction = (Action) actions.get(actionName);
        // Create the menu item
        JMenuItem menuItem = menu.add(spec.getName());
        if (targetAction != null) {
          // The editor kit knows the action
          menuItem.addActionListener(targetAction);
        } else {
          // Action not known - disable the menu item
          menuItem.setEnabled(false);
        }
      }
    }
    // Return null if nothing was added to the menu.
    if (menu.getMenuComponentCount() == 0) {
      menu = null;
    }
    return menu;
  }
}