// 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; import info.GUIConstants; import info.SysInfo; import java.awt.KeyEventPostProcessor; import java.awt.KeyboardFocusManager; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import behaviors.singleact.ExitAction; import components.waveform.MyGlassPane; import components.wordpool.WordpoolDisplay; import control.Start; /** * Main window of the program. * * <p>Every component in the frame (at any level of nesting) that can be clicked by the user (i.e., is not obscured) * must handle focus-passing, see {@link MyFocusTraversalPolicy} for details. */ public class MyFrame extends JFrame implements KeyEventPostProcessor { private static MyFrame instance; private MyFrame() { setTitle(GUIConstants.defaultFrameTitle); setGlassPane(MyGlassPane.getInstance()); MyGlassPane.getInstance().setVisible(true); setJMenuBar(MyMenu.getInstance()); //force handling by WindowListener below setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); //handle clicking on the "x" mark to close the window addWindowListener(new WindowAdapter(){ @Override public void windowClosing(WindowEvent e) { new ExitAction().actionPerformed(new ActionEvent(MyFrame.getInstance(), ActionEvent.ACTION_PERFORMED, null, System.currentTimeMillis(), 0)); } }); setContentPane(MySplitPane.getInstance()); //accept drag and drop of directories and files new FileDrop(this, new FileDropListener()); //replace the java coffee cup icon on the top left of windows in such platforms as Windows and Linux if(SysInfo.sys.isWindows7) { setIconImage(Toolkit.getDefaultToolkit().getImage( MyFrame.class.getResource("/images/headphones48.png"))); //bigger icon for windows 7's revamped task bar } else { setIconImage(Toolkit.getDefaultToolkit().getImage( MyFrame.class.getResource("/images/headphones16.png"))); } //this is default, but double checking because focusability is needed for MyFocusTraversalPolicy to be used setFocusable(true); //used to pass focus to text field when someone types outside of the field KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(this); // getRootPane().putClientProperty("apple.awt.brushMetalLook", Boolean.TRUE); } /** * Singleton accessor. * * @return The singleton <code>MyFrame</code> */ public static MyFrame getInstance() { if (instance == null) { instance = new MyFrame(); } return instance; } /** * This hears absolutely everything while the JVM has focus (includes preferences frame) * * <p>Currently this class is used to pass focus to the {@link wordpool.WordpoolTextField} when the user starts typing while <code>MyFrame</code> is selected. * Also used for focus debugging. If {@link Start#DEBUG_FOCUS} is <code>true</code> the focus owner will be printed every time a key is pressed. * * <p>Please note that arrow keys do NOT generate key typed events, so they are never consumed * Also note key typed events always have the location KeyEvent.KEY_LOCATION_UNKNOWN * Because arrow keys don't generate KeyTyped events, InputMaps are never get them. * They can be heard with KeyListeners, but those require focus, which is messy. * * <p>Unfortunately there's really no way to tell if a KeyEvent is a press, release, or type event. * We use a heuristic to avoid duplicate event handling. */ @SuppressWarnings("all") public boolean postProcessKeyEvent(KeyEvent e) { if(Start.DEBUG_FOCUS) { if(e.getKeyLocation() == KeyEvent.KEY_LOCATION_UNKNOWN) { System.out.println(getFocusOwner()); } } //best attempt to restrict us to key_typed so we don't have duplicate events for key_pressed and key_released //unfortunately, there might be press/release events with undefined/unkown codes that this condition will accept if(e.getKeyLocation() == KeyEvent.KEY_LOCATION_UNKNOWN && e.getKeyCode() == KeyEvent.VK_UNDEFINED) { if(e.getModifiers() == 0) { if(Character.isLetter(e.getKeyChar()) || Character.isDigit(e.getKeyChar())) { if(getFocusOwner() != null) { //this is how we guarantee MyFrame is "focused" and not the PreferencesFrame. not 100% cross-platform since Solaris separates the focus notion from window selection/prominence WordpoolDisplay.switchToFocus(Character.toString(e.getKeyChar())); } } } } return false; } }