Skip to content

Commit

Permalink
Integrates Emacs key bindings to JabRef
Browse files Browse the repository at this point in the history
 * adds setting to enable Emacs key bindings
 * JTextAreaWithHighlighting: Does not override existing key bindings of the field.
  • Loading branch information
koppor committed Dec 16, 2012
1 parent 6b04ef4 commit e7a27ef
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 22 deletions.
48 changes: 32 additions & 16 deletions src/java/net/sf/jabref/EntryEditorPrefsTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.xnap.commons.gui.shortcut.EmacsKeyBindings;

import net.sf.jabref.autocompleter.AbstractAutoCompleter;

import com.jgoodies.forms.builder.DefaultFormBuilder;
Expand All @@ -31,7 +33,7 @@
public class EntryEditorPrefsTab extends JPanel implements PrefsTab {

private JCheckBox autoOpenForm, showSource,
defSource, disableOnMultiple, autoComplete;
defSource, emacsMode, disableOnMultiple, autoComplete;
private JRadioButton autoCompBoth, autoCompFF, autoCompLF,
autoCompFirstNameMode_Full, autoCompFirstNameMode_Abbr, autoCompFirstNameMode_Both;
boolean oldAutoCompFF, oldAutoCompLF,
Expand Down Expand Up @@ -62,6 +64,7 @@ public EntryEditorPrefsTab(JabRefFrame frame, JabRefPreferences prefs) {
autoOpenForm = new JCheckBox(Globals.lang("Open editor when a new entry is created"));
defSource = new JCheckBox(Globals.lang("Show BibTeX source by default"));
showSource = new JCheckBox(Globals.lang("Show BibTeX source panel"));
emacsMode = new JCheckBox(Globals.lang("Use Emacs keybindings"));
disableOnMultiple = new JCheckBox(Globals.lang("Disable entry editor when multiple entries are selected"));
autoComplete = new JCheckBox(Globals.lang("Enable word/name autocompletion"));

Expand Down Expand Up @@ -105,23 +108,25 @@ public void stateChanged(ChangeEvent event) {
);

FormLayout layout = new FormLayout
("8dlu, left:pref, 8dlu, fill:150dlu, 4dlu, fill:pref", // 4dlu, left:pref, 4dlu",
(// columns
"8dlu, left:pref, 8dlu, fill:150dlu, 4dlu, fill:pref", // 4dlu, left:pref, 4dlu",
// rows 1 to 10
"pref, 6dlu, pref, 6dlu, pref, 6dlu, pref, 6dlu, pref, 6dlu, " +
// rows 11 to 20
"pref, 6dlu, pref, 6dlu, pref, 6dlu, pref, pref, pref, pref, " +
// rows 21 to 26
"6dlu, pref, pref, pref, pref");
"pref, 6dlu, pref, 6dlu, pref, 6dlu, pref, 6dlu, pref, pref, " +
// rows 21 to 27
"pref, pref, 6dlu, pref, pref, pref, pref");
DefaultFormBuilder builder = new DefaultFormBuilder(layout);
CellConstraints cc = new CellConstraints();
builder.addSeparator(Globals.lang("Editor options"), cc.xyw(1, 1, 5));
builder.add(autoOpenForm, cc.xy(2, 3));
builder.add(disableOnMultiple, cc.xy(2, 5));
builder.add(showSource, cc.xy(2, 7));
builder.add(defSource, cc.xy(2, 9));
builder.add(emacsMode, cc.xy(2, 11));

builder.addSeparator(Globals.lang("Autocompletion options"), cc.xyw(1, 11, 5));
builder.add(autoComplete, cc.xy(2, 13));
builder.addSeparator(Globals.lang("Autocompletion options"), cc.xyw(1, 13, 5));
builder.add(autoComplete, cc.xy(2, 15));

DefaultFormBuilder builder3 = new DefaultFormBuilder(new FormLayout("left:pref, 4dlu, fill:150dlu",""));
JLabel label = new JLabel(Globals.lang("Use autocompletion for the following fields")+":");
Expand All @@ -130,17 +135,17 @@ public void stateChanged(ChangeEvent event) {
JLabel label2 = new JLabel(Globals.lang("Autocomplete after following number of characters")+":");
builder3.append(label2);
builder3.append(shortestToComplete);
builder.add(builder3.getPanel(), cc.xyw(2, 15, 3));
builder.add(builder3.getPanel(), cc.xyw(2, 17, 3));

builder.addSeparator(Globals.lang("Name format used for autocompletion"), cc.xyw(2, 17, 4));
builder.add(autoCompFF, cc.xy(2,18));
builder.add(autoCompLF, cc.xy(2,19));
builder.add(autoCompBoth, cc.xy(2,20));
builder.addSeparator(Globals.lang("Name format used for autocompletion"), cc.xyw(2, 19, 4));
builder.add(autoCompFF, cc.xy(2,20));
builder.add(autoCompLF, cc.xy(2,21));
builder.add(autoCompBoth, cc.xy(2,22));

builder.addSeparator(Globals.lang("Treatment of first names"), cc.xyw(2, 22, 4));
builder.add(autoCompFirstNameMode_Abbr, cc.xy(2,23));
builder.add(autoCompFirstNameMode_Full, cc.xy(2,24));
builder.add(autoCompFirstNameMode_Both, cc.xy(2,25));
builder.addSeparator(Globals.lang("Treatment of first names"), cc.xyw(2, 24, 4));
builder.add(autoCompFirstNameMode_Abbr, cc.xy(2,25));
builder.add(autoCompFirstNameMode_Full, cc.xy(2,26));
builder.add(autoCompFirstNameMode_Both, cc.xy(2,27));

JPanel pan = builder.getPanel();
pan.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
Expand All @@ -151,6 +156,7 @@ public void setValues() {
autoOpenForm.setSelected(_prefs.getBoolean("autoOpenForm"));
defSource.setSelected(_prefs.getBoolean("defaultShowSource"));
showSource.setSelected(_prefs.getBoolean("showSource"));
emacsMode.setSelected(_prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS));
disableOnMultiple.setSelected(_prefs.getBoolean("disableOnMultipleSelection"));
autoComplete.setSelected(_prefs.getBoolean("autoComplete"));
autoCompFields.setText(_prefs.get("autoCompleteFields"));
Expand Down Expand Up @@ -184,6 +190,16 @@ else if (_prefs.get(JabRefPreferences.AUTOCOMPLETE_FIRSTNAME_MODE).equals(JabRef
public void storeSettings() {
_prefs.putBoolean("autoOpenForm", autoOpenForm.isSelected());
_prefs.putBoolean("defaultShowSource", defSource.isSelected());
if (_prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS) != emacsMode.isSelected()) {
// user has changed settings of EMACS mode
// immediately apply the change
if (emacsMode.isSelected()) {
EmacsKeyBindings.load();
} else {
EmacsKeyBindings.unload();
}
_prefs.putBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS, emacsMode.isSelected());
}
_prefs.putBoolean("disableOnMultipleSelection", disableOnMultiple.isSelected());
// We want to know if the following settings have been modified:
boolean oldAutoComplete = _prefs.getBoolean("autoComplete");
Expand Down
6 changes: 6 additions & 0 deletions src/java/net/sf/jabref/GUIGlobals.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import javax.swing.ImageIcon;
import javax.swing.JLabel;

import org.xnap.commons.gui.shortcut.EmacsKeyBindings;

import net.sf.jabref.specialfields.Priority;
import net.sf.jabref.specialfields.Quality;
import net.sf.jabref.specialfields.Rank;
Expand Down Expand Up @@ -426,6 +428,10 @@ public static void init() {
tableIcons.put(SpecialFieldsUtils.FIELDNAME_PRIORITY, lab);

//jabRefFont = new Font("arial", Font.ITALIC/*+Font.BOLD*/, 20);

if (Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS)) {
EmacsKeyBindings.load();
}
}

}
32 changes: 27 additions & 5 deletions src/java/net/sf/jabref/JTextAreaWithHighlighting.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2003-2011 JabRef contributors.
/* Copyright (C) 2003-2012 JabRef contributors.
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; either version 2 of the License, or
Expand All @@ -18,15 +18,17 @@
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.*;
import javax.swing.AbstractAction;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Document;
import javax.swing.text.Highlighter;
import javax.swing.text.Keymap;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
Expand Down Expand Up @@ -109,8 +111,28 @@ public void actionPerformed(ActionEvent evt) {
}
});

// Bind the redo action to ctl-Y
getInputMap().put(Globals.prefs.getKey("Redo"), "Redo");
// Bind the redo action to ctrl-Y
boolean bind = true;
KeyStroke redoKey = Globals.prefs.getKey("Redo");
if (Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS)) {
// If emacs is enabled, check if we have a conflict at keys
// If yes, do not bind
// Typically, we have: CTRL+y is "yank" in emacs and REDO in 'normal' settings
// The Emacs key bindings are stored in the keymap, not in the input map.
Keymap keymap2 = getKeymap();
KeyStroke[] keys = keymap2.getBoundKeyStrokes();
int i = 0;
while ((i<keys.length) && (!keys[i].equals(redoKey))) {
i++;
}
if (i<keys.length) {
// conflict found -> do not bind
bind = false;
}
}
if (bind) {
getInputMap().put(redoKey, "Redo");
}
}

/**
Expand Down
5 changes: 4 additions & 1 deletion src/java/net/sf/jabref/JabRefPreferences.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2003-2011 JabRef contributors.
/* Copyright (C) 2003-2012 JabRef contributors.
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; either version 2 of the License, or
Expand Down Expand Up @@ -70,6 +70,8 @@ public class JabRefPreferences {

SHOWONELETTERHEADINGFORICONCOLUMNS = "showOneLetterHeadingForIconColumns",

EDITOR_EMACS_KEYBINDINGS = "editorEMACSkeyBindings",

SHORTEST_TO_COMPLETE = "shortestToComplete",
AUTOCOMPLETE_FIRSTNAME_MODE = "autoCompFirstNameMode",
// here are the possible values for _MODE:
Expand Down Expand Up @@ -248,6 +250,7 @@ private JabRefPreferences() {
defaults.put("highLightWords", Boolean.TRUE);
defaults.put("searchPanePosX", new Integer(0));
defaults.put("searchPanePosY", new Integer(0));
defaults.put(EDITOR_EMACS_KEYBINDINGS, Boolean.FALSE);
defaults.put("autoComplete", Boolean.TRUE);
defaults.put("autoCompleteFields", "author;editor;title;journal;publisher;keywords;crossref");
defaults.put("autoCompFF", Boolean.FALSE); // "Autocomplete names in 'Firstname Lastname' format only"
Expand Down
5 changes: 5 additions & 0 deletions src/java/org/xnap/commons/gui/shortcut/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* This package is a subset of the same package of XNap Commons (http://xnap-commons.sourceforge.net/)
* License: LGPL 2.1
*/
package org.xnap.commons.gui.shortcut;
1 change: 1 addition & 0 deletions src/txt/CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[master branch]
- Added support for Emacs key bindings at the entry editor
- Added a formatter for units which keeps the case and adds non-breaking separators
- Added a Merge entries functionality
- Added a setting to choose either a DOI link or a URL to be standard (feature 710)
Expand Down

0 comments on commit e7a27ef

Please sign in to comment.