// This file is part of Penn TotalRecall <http://memory.psych.upenn.edu/TotalRecall>. // // TotalRecall 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, version 3 only. // // TotalRecall 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 TotalRecall. If not, see <http://www.gnu.org/licenses/>. package components.wordpool; import info.SysInfo; import info.UserPrefs; import java.awt.AWTKeyStroke; import java.awt.Dimension; import java.awt.KeyboardFocusManager; import java.awt.event.ActionEvent; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.HashSet; import java.util.Set; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.text.Keymap; import behaviors.multiact.AnnotateAction; import components.MyFrame; /** * Custom <code>JTextField</code> for entering annotations. * * Includes features to aid in annotation speed and accuracy that were added to PyParse over the years. * * @author Yuvi Masory */ public class WordpoolTextField extends JTextField implements KeyListener, FocusListener { private static WordpoolTextField instance; private String clipboard = ""; private WordpoolTextField(){ setPreferredSize(new Dimension(Integer.MAX_VALUE, 30)); setMaximumSize(new Dimension(Integer.MAX_VALUE, 30)); getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "annotate regular"); getActionMap().put("annotate regular", new AnnotateAction(AnnotateAction.Mode.REGULAR)); Set<AWTKeyStroke> keys = new HashSet<AWTKeyStroke>(); keys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, InputEvent.CTRL_MASK, false)); setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keys); addKeyListener(this); //emacs key bindings if(UserPrefs.prefs.getBoolean(UserPrefs.useEmacs, UserPrefs.defaultUseEmacs)) { JTextComponent.KeyBinding[] newBindings = { new JTextComponent.KeyBinding( KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK, false), DefaultEditorKit.beginLineAction), new JTextComponent.KeyBinding( KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_MASK, false), DefaultEditorKit.endLineAction), new JTextComponent.KeyBinding( KeyStroke.getKeyStroke(KeyEvent.VK_B, InputEvent.CTRL_MASK, false), DefaultEditorKit.backwardAction), new JTextComponent.KeyBinding( KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK, false), DefaultEditorKit.forwardAction), new JTextComponent.KeyBinding( KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_MASK, false), DefaultEditorKit.deleteNextCharAction)}; Keymap k = getKeymap(); JTextComponent.loadKeymap(k, newBindings, getActions()); } addFocusListener(this); getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.SHIFT_DOWN_MASK, false), "none"); getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.SHIFT_DOWN_MASK, false), "none"); getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, SysInfo.sys.menuKey, false), "none"); getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, SysInfo.sys.menuKey, false), "none"); getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, SysInfo.sys.menuKey + InputEvent.SHIFT_DOWN_MASK, false), "none"); getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, SysInfo.sys.menuKey + InputEvent.SHIFT_DOWN_MASK, false), "none"); getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), "clear"); getActionMap().put("clear", new AbstractAction() { public void actionPerformed(ActionEvent e) { setText(""); MyFrame.getInstance().requestFocusInWindow(); } }); } @Override protected Document createDefaultModel() { return new WordpoolDocument(); } public void keyPressed(KeyEvent e) { if(e.getModifiers() == 0) { // no modifiers if(e.getKeyCode() == KeyEvent.VK_TAB) { if(getText().length() == 0) { getFocusCycleRootAncestor().getFocusTraversalPolicy().getComponentAfter( getFocusCycleRootAncestor(), this).requestFocusInWindow(); return; } WordpoolWord firstWord = WordpoolList.getFirstWord(); if(firstWord == null) { return; } String candidate = firstWord.getText(); if(candidate != null) { setText(candidate); } } if(e.getKeyCode() == KeyEvent.VK_SPACE) { e.consume(); } if(e.getKeyCode() == KeyEvent.VK_DOWN) { if(WordpoolList.getInstance().getModel().getSize() > 0) { WordpoolList.getInstance().requestFocusInWindow(); } } //this assumes backspace will actually remove the previous element, but we'll make that bet //alternative is WordpoolDocument.removeUpdate(), but that is called by programmatic changes to textfield too if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { if(getText().length() <= 1) { MyFrame.getInstance().requestFocusInWindow(); } } } //emacs key bindings if(e.getModifiers() == InputEvent.CTRL_MASK) { if(e.getKeyCode() == KeyEvent.VK_K) { emacsKillLine(); } else if (e.getKeyCode() == KeyEvent.VK_Y) { emacsYank(); } } } private void emacsYank() { setText(getText() + clipboard); } private void emacsKillLine() { int pos = getCaretPosition(); clipboard = getText().substring(pos, getText().length()); setText(getText().substring(0, pos)); } public void keyReleased(KeyEvent e) {} public void keyTyped(KeyEvent e) {} protected static WordpoolTextField getInstance() { if(instance == null) { instance = new WordpoolTextField(); } return instance; } public static WordpoolTextField getFocusTraversalReference() { return getInstance(); } public void focusGained(FocusEvent e) { setSelectionStart(0); setSelectionEnd(0); setCaretPosition(getText().length()); } public void focusLost(FocusEvent e) {} }