/* * Created on Jun 7, 2005 * */ package net.atlanticbb.tantlinger.ui.text; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.Vector; import javax.swing.Action; import javax.swing.KeyStroke; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; import javax.swing.text.Document; import javax.swing.text.TextAction; import javax.swing.undo.CannotUndoException; import javax.swing.undo.CompoundEdit; import javax.swing.undo.UndoManager; import javax.swing.undo.UndoableEdit; import org.bushe.swing.action.ActionManager; import net.atlanticbb.tantlinger.i18n.I18n; import net.atlanticbb.tantlinger.ui.UIUtils; //TODO add static method to unregister documents /** * Manages compound undoable edits. * * Before an undoable edit happens on a particular document, you should call * the static method CompoundUndoManager.beginCompoundEdit(doc) * * Conversely after an undoable edit happens on a particular document, * you shoulc call the static method CompoundUndoManager.beginCompoundEdit(doc) * * For either of these methods to work, you must add an instance of * CompoundUndoManager as a document listener... e.g * * doc.addUndoableEditListener(new CompoundUndoManager(doc, new UndoManager()); * * Note that each CompoundUndoManager should have its own UndoManager. * * * @author Bob Tantlinger */ public class CompoundUndoManager implements UndoableEditListener { private static final I18n i18n = I18n.getInstance("net.atlanticbb.tantlinger.ui.text"); /** * Static undo action that works across all documents * with a CompoundUndoManager registered as an UndoableEditListener */ public static Action UNDO = new UndoAction(); /** * Static undo action that works across all documents * with a CompoundUndoManager registered as an UndoableEditListener */ public static Action REDO = new RedoAction(); private UndoManager undoer; private CompoundEdit compoundEdit = null; private Document document = null; private static Vector docs = new Vector(); private static Vector lsts = new Vector(); private static Vector undoers = new Vector(); protected static void registerDocument(Document doc, CompoundUndoManager lst, UndoManager um) { docs.add(doc); lsts.add(lst); undoers.add(um); } /** * Gets the undo manager for a document that has a CompoundUndoManager * as an UndoableEditListener * @param doc * @return The registed undomanger for the document */ public static UndoManager getUndoManagerForDocument(Document doc) { for(int i = 0; i < docs.size(); i++) { if(docs.elementAt(i) == doc) return (UndoManager)undoers.elementAt(i); } return null; } /** * Notifies the CompoundUndoManager for the specified Document that * a compound edit is about to begin. * * @param doc */ public static void beginCompoundEdit(Document doc) { for(int i = 0; i < docs.size(); i++) { if(docs.elementAt(i) == doc) { CompoundUndoManager l = (CompoundUndoManager)lsts.elementAt(i); l.beginCompoundEdit(); return; } } } /** * Notifies the CompoundUndoManager for the specified Document that * a compound edit is complete. * * @param doc */ public static void endCompoundEdit(Document doc) { for(int i = 0; i < docs.size(); i++) { if(docs.elementAt(i) == doc) { CompoundUndoManager l = (CompoundUndoManager)lsts.elementAt(i); l.endCompoundEdit(); return; } } } /** * Updates the enabled states of the UNDO and REDO actions * for the specified document * @param doc */ public static void updateUndo(Document doc) { UndoManager um = getUndoManagerForDocument(doc); if(um != null) { UNDO.setEnabled(um.canUndo()); REDO.setEnabled(um.canRedo()); } } /** * Discards all edits for the specified Document * * @param doc */ public static void discardAllEdits(Document doc) { UndoManager um = getUndoManagerForDocument(doc); if(um != null) { um.discardAllEdits(); UNDO.setEnabled(um.canUndo()); REDO.setEnabled(um.canRedo()); } } /** * Creates a new CompoundUndoManager * * @param doc * @param um The UndoManager to use for this document */ public CompoundUndoManager(Document doc, UndoManager um) { undoer = um; document = doc; registerDocument(document, this, undoer); } /** * Creates a new CompoundUndoManager * @param doc */ public CompoundUndoManager(Document doc) { this(doc, new UndoManager()); } public void undoableEditHappened(UndoableEditEvent evt) { UndoableEdit edit = evt.getEdit(); if(compoundEdit != null) { //System.out.println("adding to compound"); compoundEdit.addEdit(edit); } else { undoer.addEdit(edit); updateUndo(document); } } protected void beginCompoundEdit() { //System.out.println("starting compound"); compoundEdit = new CompoundEdit(); } protected void endCompoundEdit() { //System.out.println("ending compound"); if(compoundEdit != null) { compoundEdit.end(); undoer.addEdit(compoundEdit); updateUndo(document); } compoundEdit = null; } static class UndoAction extends TextAction { /** * */ private static final long serialVersionUID = 1L; public UndoAction() { super(i18n.str("undo")); putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "undo.png")); putValue(ActionManager.LARGE_ICON, UIUtils.getIcon(UIUtils.X24, "undo.png")); putValue(MNEMONIC_KEY, new Integer(i18n.mnem("undo"))); setEnabled(false); putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_MASK)); putValue(SHORT_DESCRIPTION, getValue(NAME)); } public void actionPerformed(ActionEvent e) { Document doc = getTextComponent(e).getDocument(); UndoManager um = getUndoManagerForDocument(doc); if(um != null) { try { um.undo(); } catch (CannotUndoException ex) { System.out.println("Unable to undo: " + ex); ex.printStackTrace(); } updateUndo(doc); } } } static class RedoAction extends TextAction { /** * */ private static final long serialVersionUID = 1L; public RedoAction() { super(i18n.str("redo")); putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "redo.png")); putValue(ActionManager.LARGE_ICON, UIUtils.getIcon(UIUtils.X24, "redo.png")); putValue(MNEMONIC_KEY, new Integer(i18n.mnem("redo"))); setEnabled(false); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_Y, InputEvent.CTRL_MASK)); putValue(SHORT_DESCRIPTION, getValue(NAME)); } public void actionPerformed(ActionEvent e) { Document doc = getTextComponent(e).getDocument(); UndoManager um = getUndoManagerForDocument(doc); if(um != null) { try { um.redo(); } catch (CannotUndoException ex) { System.out.println("Unable to redo: " + ex); ex.printStackTrace(); } updateUndo(doc); } } } }