« インスペクタのデザイン | トップページ | フォーカス処理の見直し »

2017年1月13日 (金)

JTextComponent の undo

オリジナルでは 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 や,CellEditorTreeCellEditor にも組み込んで,ほぼ全てのテキスト入力で undo できるようになった。

« インスペクタのデザイン | トップページ | フォーカス処理の見直し »

OpenDolphin」カテゴリの記事