// 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.GUIConstants; import info.MyShapes; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.List; import javax.swing.BoxLayout; import javax.swing.JPanel; import javax.swing.JTextField; /** * A custom interface component for displaying wordpool and lst words to the user and a text field in which to enter annotations. * * The component supports tab auto-complete of words being entered in the text field, using words from the wordpool list display. * The user is forced to choose only words from the list, to do otherwise requires marking the word as an intrusion with a special keystroke. * The display is self-sorting, with lst words above regular wordpool words, and alphabetical otherwise. * * <p>Note: Access to this component from outside the package is limited to the public static methods provided in this class. * Code outside the package cannot and should not try to access the internal list, model, or other components directly. * * @author Yuvi Masory * */ public class WordpoolDisplay extends JPanel { private static final String title = "Wordpool"; private static JTextField field; private static WordpoolDisplay instance; private static WordpoolScrollPane pane; /** * Creates a new instance of the component, initializing internal components, listeners, and various aspects of appearance. */ private WordpoolDisplay() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); field = WordpoolTextField.getInstance(); pane = new WordpoolScrollPane(); add(field); add(pane); setPreferredSize(GUIConstants.wordpoolDisplayDimension); setMaximumSize(GUIConstants.wordpoolDisplayDimension); setBorder(MyShapes.createMyUnfocusedTitledBorder(title)); //since WordpoolDisplay is a clickable area, we must write focus handling code for the event it is clicked on //this case is rare, since only a very small amount of this component is exposed (the area around the border title), //the rest being obscured by the WordpoolList and WordpoolTextField addMouseListener(new MouseAdapter(){ @Override public void mousePressed(MouseEvent e) { field.requestFocusInWindow(); } }); } /** * Public accessor to the <code>WordpoolTextField</code>'s text. * * @return WordpoolTextField.getInstance().getText() */ public static String getFieldText() { return WordpoolTextField.getInstance().getText(); } /** * Sets the <code>WordpoolTextField</code>'s text to the empty string. */ public static void clearText() { WordpoolTextField.getInstance().setText(""); } public static void distinguishAsLst(List<WordpoolWord> lstWords) { WordpoolList.getInstance().getModel().distinguishAsLst(lstWords); } public static void undistinguishAllWords() { WordpoolList.getInstance().getModel().undistinguishAllWords(); } /** * Removes all <code>WordpoolWords</code> from the component, * whether or not they are present graphically or hidden (because of auto-complete filtering). */ public static void removeAllWords() { WordpoolList.getInstance().getModel().removeAllWords(); } /** * Adds the provided <code>WordpoolWords</code> to the component for display. * * @param words */ public static void addWordpoolWords(List<WordpoolWord> words) { WordpoolList.getInstance().getModel().addElements(words); } /** * Finds the alphabetically first <code>WordpoolWord</code> that matches the provided <code>String</code>. * * @param str The <code>String</code> to be matched, often the contents of the <code>WordpoolTextField</code> * @return The first alphabetical matching <code>WordpoolWord</code>, or <code>null</code> if there is no match */ public static WordpoolWord findMatchingWordpooWord(String str) { return WordpoolList.getInstance().getModel().findMatchingWordpoolWord(str); } /** * Called by outside key listeners when the user types alphanumeric characters. * The idea is to pass focus to the text field and enter the string programmatically that the user had started typing * before the field had focus. * This is a convenience feature so the user doesn't have to manually give the field focus to enter something. * * Does nothing if the <code>WordpoolTextField</code> already has focus. * * @param str The String the user typed, possibly before the <code>WordpoolTextField</code> had focus. */ public static void switchToFocus(String str) { if(field.hasFocus() == false) { //don't double-add strings that will be added by the field automatically! field.setText(field.getText() + str); field.requestFocusInWindow(); } } public static void switchToFocusAndClobber(String str) { if(field.hasFocus() == false) { //don't double-add strings that will be added by the field automatically! field.setText(str); field.requestFocusInWindow(); } } /** * Singleton accessor * * @return The singleton <code>WordpoolDisplay</code> */ public static WordpoolDisplay getInstance() { if (instance == null) { instance = new WordpoolDisplay(); } return instance; } public static void setInputEnabled(boolean enabled) { WordpoolTextField.getInstance().setEnabled(enabled); } }