EmacsKeyBindings.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
org.xnap.gui.util |
![]() |
![]() |
XNap 3 |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* XNap - A P2P framework and client.
*
* See the file AUTHORS for copyright information.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.xnap.gui.util;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Iterator;
import java.util.LinkedList;
import javax.swing.Action;
import javax.swing.JEditorPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import javax.swing.text.TextAction;
import javax.swing.text.Utilities;
import org.apache.log4j.Logger;
/**
* Generic class which activates Emacs keybindings for java input {@link
* JTextComponent}s.
*
* TODO: Some actions don't work at the end of line, that's because they
* depend on built-in actions.
*/
public class EmacsKeyBindings
{
//--- Constant(s) ---
public static final String killLineAction = "emacs-kill-line";
public static final String killRingSaveAction = "emacs-kill-ring-save";
public static final String killRegionAction = "emacs-kill-region";
public static final String backwardKillWordAction
= "emacs-backward-kill-word";
public static final String capitalizeWordAction = "emacs-capitalize-word";
public static final String downcaseWordAction = "emacs-downcase-word";
public static final String killWordAction = "emacs-kill-word";
public static final String setMarkCommandAction
= "emacs-set-mark-command";
public static final String yankAction = "emacs-yank";
public static final String yankPopAction = "emacs-yank-pop";
public static final String upcaseWordAction = "emacs-upcase-word";
public static final JTextComponent.KeyBinding[] EMACS_KEY_BINDINGS = {
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_Y,
InputEvent.CTRL_MASK),
DefaultEditorKit.pasteAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W,
InputEvent.ALT_MASK),
DefaultEditorKit.copyAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W,
InputEvent.CTRL_MASK),
DefaultEditorKit.cutAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_E,
InputEvent.CTRL_MASK),
DefaultEditorKit.endLineAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_A,
InputEvent.CTRL_MASK),
DefaultEditorKit.beginLineAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_D,
InputEvent.CTRL_MASK),
DefaultEditorKit.deleteNextCharAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_N,
InputEvent.CTRL_MASK),
DefaultEditorKit.downAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_P,
InputEvent.CTRL_MASK),
DefaultEditorKit.upAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_B,
InputEvent.ALT_MASK),
DefaultEditorKit.previousWordAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LESS,
InputEvent.ALT_MASK),
DefaultEditorKit.beginAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LESS,
InputEvent.ALT_MASK
+ InputEvent.SHIFT_MASK),
DefaultEditorKit.endAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_F,
InputEvent.ALT_MASK),
DefaultEditorKit.nextWordAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_F,
InputEvent.CTRL_MASK),
DefaultEditorKit.forwardAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_B,
InputEvent.CTRL_MASK),
DefaultEditorKit.backwardAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V,
InputEvent.CTRL_MASK),
DefaultEditorKit.pageDownAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V,
InputEvent.ALT_MASK),
DefaultEditorKit.pageUpAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_D,
InputEvent.ALT_MASK),
EmacsKeyBindings.killWordAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE,
InputEvent.ALT_MASK),
EmacsKeyBindings.backwardKillWordAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,
InputEvent.CTRL_MASK),
EmacsKeyBindings.setMarkCommandAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W,
InputEvent.ALT_MASK),
EmacsKeyBindings.killRingSaveAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W,
InputEvent.CTRL_MASK),
EmacsKeyBindings.killRegionAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_K,
InputEvent.CTRL_MASK),
EmacsKeyBindings.killLineAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_Y,
InputEvent.CTRL_MASK),
EmacsKeyBindings.yankAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_Y,
InputEvent.ALT_MASK),
EmacsKeyBindings.yankPopAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_C,
InputEvent.ALT_MASK),
EmacsKeyBindings.capitalizeWordAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_L,
InputEvent.ALT_MASK),
EmacsKeyBindings.downcaseWordAction),
new JTextComponent.
KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_U,
InputEvent.ALT_MASK),
EmacsKeyBindings.upcaseWordAction),
};
//--- Data field(s) ---
private static Logger logger = Logger.getLogger(EmacsKeyBindings.class);
//--- Constructor(s) ---
//--- Method(s) ---
public static void load()
{
JTextComponent[] jtcs = new JTextComponent[] {
new JTextArea(),
new JTextPane(),
new JTextField(),
new JEditorPane(),
};
for (int i = 0; i < jtcs.length; i++) {
Keymap orig = jtcs[i].getKeymap();
Keymap backup = JTextComponent.addKeymap
(jtcs[i].getClass().getName(), null);
Action[] bound = orig.getBoundActions();
for (int j = 0; j < bound.length; j++) {
KeyStroke[] strokes = orig.getKeyStrokesForAction(bound[j]);
for (int k = 0; k < strokes.length; k++) {
backup.addActionForKeyStroke(strokes[k], bound[j]);
}
}
backup.setDefaultAction(orig.getDefaultAction());
}
loadEmacsKeyBindings();
}
public static void unload()
{
JTextComponent[] jtcs = new JTextComponent[] {
new JTextArea(),
new JTextPane(),
new JTextField(),
new JEditorPane(),
};
for (int i = 0; i < jtcs.length; i++) {
Keymap backup = JTextComponent.getKeymap
(jtcs[i].getClass().getName());
if (backup != null) {
Keymap current = jtcs[i].getKeymap();
current.removeBindings();
Action[] bound = backup.getBoundActions();
for (int j = 0; j < bound.length; j++) {
KeyStroke[] strokes =
backup.getKeyStrokesForAction(bound[i]);
for (int k = 0; k < strokes.length; k++) {
current.addActionForKeyStroke(strokes[k], bound[j]);
}
}
current.setDefaultAction(backup.getDefaultAction());
}
}
}
/**
* Activates Emacs keybindings for all text components extending {@link
* JTextComponent}.
*/
private static void loadEmacsKeyBindings()
{
logger.debug("Loading emacs keybindings");
JTextComponent[] jtcs = new JTextComponent[] {
new JTextArea(),
new JTextPane(),
new JTextField(),
new JEditorPane(),
};
for (int i = 0; i < jtcs.length; i++) {
Keymap k = jtcs[i].getKeymap();
JTextComponent.loadKeymap(k, EMACS_KEY_BINDINGS,
jtcs[i].getActions());
k.addActionForKeyStroke(KeyStroke.getKeyStroke
(KeyEvent.VK_D, InputEvent.ALT_MASK),
new KillWordAction(killWordAction));
k.addActionForKeyStroke(KeyStroke.getKeyStroke
(KeyEvent.VK_BACK_SPACE,
InputEvent.ALT_MASK),
new BackwardKillWordAction(backwardKillWordAction));
k.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,
InputEvent.CTRL_MASK),
new SetMarkCommandAction(setMarkCommandAction));
k.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_W,
InputEvent.ALT_MASK),
new KillRingSaveAction(killRingSaveAction));
k.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_W,
InputEvent.CTRL_MASK),
new KillRegionAction(killRegionAction));
k.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_K,
InputEvent.CTRL_MASK),
new KillLineAction(killLineAction));
k.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_Y,
InputEvent.CTRL_MASK),
new YankAction("emacs-yank"));
k.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_Y,
InputEvent.ALT_MASK),
new YankPopAction("emacs-yank-pop"));
k.addActionForKeyStroke
(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.ALT_MASK),
new CapitalizeWordAction(capitalizeWordAction));
k.addActionForKeyStroke
(KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.ALT_MASK),
new DowncaseWordAction(downcaseWordAction));
k.addActionForKeyStroke
(KeyStroke.getKeyStroke(KeyEvent.VK_U, InputEvent.ALT_MASK),
new UpcaseWordAction(upcaseWordAction));
}
}
//--- Inner Class(es) ---
/**
* Kills the next word.
*/
public static class KillWordAction extends TextAction
{
public KillWordAction(String nm)
{
super(nm);
}
public void actionPerformed(ActionEvent e)
{
JTextComponent jtc = getTextComponent(e);
if (jtc != null) {
try {
int offs = jtc.getCaretPosition();
jtc.setSelectionStart(offs);
offs = Utilities.getNextWord(jtc, offs);
jtc.setSelectionEnd(offs);
jtc.cut();
}
catch (BadLocationException ble) {
jtc.getToolkit().beep();
}
}
}
}
/**
* Kills the previous word.
*/
public static class BackwardKillWordAction extends TextAction
{
public BackwardKillWordAction(String nm)
{
super(nm);
}
public void actionPerformed(ActionEvent e)
{
JTextComponent jtc = getTextComponent(e);
if (jtc != null) {
try {
int offs = jtc.getCaretPosition();
jtc.setSelectionEnd(offs);
offs = Utilities.getPreviousWord(jtc, offs);
jtc.setSelectionStart(offs);
jtc.cut();
}
catch (BadLocationException ble) {
jtc.getToolkit().beep();
}
}
}
}
/**
* Copies the marked region and stores it in the killring.
*/
public static class KillRingSaveAction extends TextAction
{
public KillRingSaveAction(String nm)
{
super(nm);
}
public void actionPerformed(ActionEvent e)
{
JTextComponent jtc = getTextComponent(e);
if (jtc != null && SetMarkCommandAction.isMarked(jtc)) {
jtc.setSelectionStart(SetMarkCommandAction.getCaretPosition());
jtc.moveCaretPosition(jtc.getCaretPosition());
jtc.copy();
YankAction.add(jtc.getSelectedText());
SetMarkCommandAction.reset();
// todo reset selection
}
}
}
/**
* Kills the marked region and stores it in the killring.
*/
public static class KillRegionAction extends TextAction
{
public KillRegionAction(String nm)
{
super(nm);
}
public void actionPerformed(ActionEvent e)
{
JTextComponent jtc = getTextComponent(e);
if (jtc != null && SetMarkCommandAction.isMarked(jtc)) {
jtc.setSelectionStart(SetMarkCommandAction.getCaretPosition());
jtc.moveCaretPosition(jtc.getCaretPosition());
SetMarkCommandAction.reset();
YankAction.add(jtc.getSelectedText());
jtc.cut();
}
}
}
/**
* Kills text up to the end of the current line and stores it in the
* killring.
*/
public static class KillLineAction extends TextAction
{
public KillLineAction(String nm)
{
super(nm);
}
public void actionPerformed(ActionEvent e)
{
JTextComponent jtc = getTextComponent(e);
if (jtc != null) {
try {
int start = jtc.getCaretPosition();
int end = Utilities.getRowEnd(jtc, start);
if (start == end && jtc.isEditable()) {
Document doc = jtc.getDocument();
doc.remove(end, 1);
}
else {
jtc.setSelectionStart(start);
jtc.setSelectionEnd(end);
YankAction.add(jtc.getSelectedText());
jtc.cut();
// jtc.replaceSelection("");
}
}
catch (BadLocationException ble) {
jtc.getToolkit().beep();
}
}
}
}
/**
* Sets a beginning mark.
*/
public static class SetMarkCommandAction extends TextAction
{
//--- Constant(s) ---
//--- Data field(s) ---
private static int position = -1;
private static JTextComponent jtc;
//--- Constructor(s) ---
public SetMarkCommandAction(String nm)
{
super(nm);
}
//--- Method(s) ---
public void actionPerformed(ActionEvent e)
{
jtc = getTextComponent(e);
if (jtc != null) {
position = jtc.getCaretPosition();
}
}
public static boolean isMarked(JTextComponent jt)
{
return (jtc == jt && position != -1);
}
public static void reset()
{
jtc = null;
position = -1;
}
public static int getCaretPosition()
{
return position;
}
}
/**
* Pastes text from killring.
*/
public static class YankAction extends TextAction
{
public static LinkedList killring = new LinkedList();
public static int start = -1;
public static int end = -1;
public YankAction(String nm)
{
super(nm);
}
public void actionPerformed(ActionEvent event)
{
JTextComponent jtc = getTextComponent(event);
if (jtc != null) {
try {
start = jtc.getCaretPosition();
jtc.paste();
end = jtc.getCaretPosition();
add(jtc.getText(start, end));
}
catch (Exception e) {
}
}
}
/**
* Uniquely adds <code>item</code> to killring, i.e. if
* <code>item</code> is already in killring, it's moved to the front,
* otherwise it's added as first element.
*/
public static void add(String item)
{
for (Iterator i = killring.iterator(); i.hasNext();) {
if (item.equals((String)i.next())) {
i.remove();
break;
}
}
killring.addFirst(item);
}
/**
* Returns killring successor of <code>item</code> and adds
* <code>item</code> to killring.
*
* @param predecessor
* @return Returns first item if <code>item == null</code>.
*/
public static String getNext(String predecessor)
{
if (killring.size() == 0) {
return null;
}
if (predecessor == null) {
return (String)killring.getFirst();
}
for (Iterator i = killring.iterator(); i.hasNext();) {
if (predecessor.equals((String)i.next())) {
i.remove();
if (i.hasNext()) {
String result = (String)i.next();
killring.addFirst(predecessor);
return result;
}
else {
break;
}
}
}
if (killring.size() == 0) {
return null;
}
String result = (String)killring.getFirst();
killring.addFirst(predecessor);
return result;
}
}
/**
* Pastes an element from the killring cycling through it.
*/
public static class YankPopAction extends TextAction
{
public YankPopAction(String nm)
{
super(nm);
}
public void actionPerformed(ActionEvent event)
{
JTextComponent jtc = getTextComponent(event);
if (jtc != null && YankAction.killring.size() > 0) {
jtc.setSelectionStart(YankAction.start);
jtc.setSelectionEnd(YankAction.end);
String toYank = YankAction.getNext(jtc.getSelectedText());
if (toYank != null) {
jtc.replaceSelection(toYank);
YankAction.end = jtc.getCaretPosition();
}
else {
jtc.getToolkit().beep();
}
}
}
}
/**
* Capitalizes the next word.
*/
public static class CapitalizeWordAction extends TextAction
{
public CapitalizeWordAction(String nm)
{
super(nm);
}
/**
* At first the same code as in {@link
* EmacsKeyBindings.DowncaseWordAction} is performed, to ensure the
* word is in lower case, then the first letter is capialized. */
public void actionPerformed(ActionEvent event)
{
JTextComponent jtc = getTextComponent(event);
if (jtc != null) {
try {
/* downcase code */
int start = jtc.getCaretPosition();
int end = Utilities.getNextWord(jtc, start);
jtc.setSelectionStart(start);
jtc.setSelectionEnd(end);
String word = jtc.getText(start, end - start);
jtc.replaceSelection(word.toLowerCase());
/* actual capitalize code */
int offs = Utilities.getWordStart(jtc, start);
// get first letter
String c = jtc.getText(offs, 1);
// we're at the end of the previous word
if (c.equals(" ")) {
/* ugly java workaround to get the beginning of the
word. */
offs = Utilities.getWordStart(jtc, ++offs);
c = jtc.getText(offs, 1);
}
if (Character.isLetter(c.charAt(0))) {
jtc.setSelectionStart(offs);
jtc.setSelectionEnd(offs + 1);
jtc.replaceSelection(c.toUpperCase());
}
end = Utilities.getWordEnd(jtc, offs);
jtc.setCaretPosition(end);
}
catch (BadLocationException ble) {
jtc.getToolkit().beep();
}
}
}
}
/**
* Renders all characters of the next word to lowercase.
*/
public static class DowncaseWordAction extends TextAction
{
public DowncaseWordAction(String nm)
{
super(nm);
}
public void actionPerformed(ActionEvent event)
{
JTextComponent jtc = getTextComponent(event);
if (jtc != null) {
try {
int start = jtc.getCaretPosition();
int end = Utilities.getNextWord(jtc, start);
jtc.setSelectionStart(start);
jtc.setSelectionEnd(end);
String word = jtc.getText(start, end - start);
jtc.replaceSelection(word.toLowerCase());
}
catch (BadLocationException ble) {
jtc.getToolkit().beep();
}
}
}
}
/**
* Renders all characters of the next word to upppercase.
*/
public static class UpcaseWordAction extends TextAction
{
public UpcaseWordAction(String nm)
{
super(nm);
}
public void actionPerformed(ActionEvent event)
{
JTextComponent jtc = getTextComponent(event);
if (jtc != null) {
try {
int start = jtc.getCaretPosition();
int end = Utilities.getNextWord(jtc, start);
jtc.setSelectionStart(start);
jtc.setSelectionEnd(end);
String word = jtc.getText(start, end - start);
jtc.replaceSelection(word.toUpperCase());
}
catch (BadLocationException ble) {
jtc.getToolkit().beep();
}
}
}
}
}
The table below shows all metrics for EmacsKeyBindings.java.




