オリジナルでは KartePane のみ ChartMediator 内で undo 機能が付けられていたが,JTextComponentUndoManager を作って undo 機能を独立させ,MemoInspector,TextStampEditor にも undo 機能を付けた。
package open.dolphin.helper;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.event.UndoableEditEvent;
import javax.swing.text.JTextComponent;
import javax.swing.undo.UndoManager;
/**
* JTextComponent に Undo 機能を付ける.<br>
* 使用例:
* <pre>{@code
* TextComponentUndoManager manager = new TextComponentUndoManager();
* JTextPane textComponent = new JTextPane();
* manager.addUndoActionTo(textComponent);
* textComponent.getDocument().addUndoableEditListener(manager::listener);
* }</pre>
* @author pns
*/
public class TextComponentUndoManager extends UndoManager {
private static final long serialVersionUID = 1L;
private Action undoAction;
private Action redoAction;
public TextComponentUndoManager() {
// default undo action
undoAction = new AbstractAction("undo") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
undo();
}
};
// default redo action
redoAction = new AbstractAction("redo") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
redo();
}
};
}
/**
* JTextComponent に Undo 機能を付ける utility static method.
* @param c
* @return
*/
public static TextComponentUndoManager getManager(JTextComponent c) {
TextComponentUndoManager manager = new TextComponentUndoManager();
manager.addUndoActionTo(c);
c.getDocument().addUndoableEditListener(manager::listener);
return manager;
}
public void addUndoActionTo(JTextComponent c) {
ActionMap am = c.getActionMap();
InputMap im = c.getInputMap();
am.put("undo", undoAction);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK), "undo");
am.put("redo", redoAction);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK), "redo");
}
public void setUndoAction(Action action) {
undoAction = action;
}
public void setRedoAction(Action action) {
redoAction = action;
}
public void listener (UndoableEditEvent e) {
addEdit(e.getEdit());
updateActionStatus(); // 文字入力毎に action が enable/disable される
}
@Override
public void undo() {
if (canUndo()) { super.undo(); }
updateActionStatus();
}
@Override
public void redo() {
if (canRedo()) { super.redo(); }
updateActionStatus();
}
private void updateActionStatus() {
undoAction.setEnabled(canUndo());
redoAction.setEnabled(canRedo());
}
}
追記
PatientSearchPanel の JTextField や,
CellEditor,
TreeCellEditor にも組み込んで,ほぼ全てのテキスト入力で undo できるようになった。