1 /* 2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.java.swing.plaf.windows; 27 28 import java.awt.Component; 29 import java.awt.Container; 30 import java.awt.Event; 31 import java.awt.KeyEventPostProcessor; 32 import java.awt.Window; 33 import java.awt.Toolkit; 34 35 import sun.awt.AWTAccessor; 36 import sun.awt.SunToolkit; 37 38 import java.awt.event.ActionEvent; 39 import java.awt.event.KeyEvent; 40 41 import javax.swing.AbstractAction; 42 import javax.swing.ActionMap; 43 import javax.swing.InputMap; 44 import javax.swing.KeyStroke; 45 import javax.swing.JComponent; 46 import javax.swing.JLabel; 47 import javax.swing.JRootPane; 48 import javax.swing.SwingUtilities; 49 import javax.swing.UIManager; 50 import javax.swing.AbstractButton; 51 import javax.swing.JFrame; 52 import javax.swing.JMenu; 53 import javax.swing.JMenuBar; 54 import javax.swing.MenuElement; 55 import javax.swing.MenuSelectionManager; 56 57 import javax.swing.plaf.ActionMapUIResource; 58 import javax.swing.plaf.ComponentUI; 59 import javax.swing.plaf.InputMapUIResource; 60 61 import javax.swing.plaf.basic.BasicRootPaneUI; 62 import javax.swing.plaf.basic.ComboPopup; 63 64 /** 65 * Windows implementation of RootPaneUI, there is one shared between all 66 * JRootPane instances. 67 * 68 * @author Mark Davidson 69 * @since 1.4 70 */ 71 public class WindowsRootPaneUI extends BasicRootPaneUI { 72 73 private static final WindowsRootPaneUI windowsRootPaneUI = new WindowsRootPaneUI(); 74 static final AltProcessor altProcessor = new AltProcessor(); 75 76 public static ComponentUI createUI(JComponent c) { 77 return windowsRootPaneUI; 78 } 79 80 static class AltProcessor implements KeyEventPostProcessor { 81 static boolean altKeyPressed = false; 82 static boolean menuCanceledOnPress = false; 83 static JRootPane root = null; 84 static Window winAncestor = null; 85 86 void altPressed(KeyEvent ev) { 87 MenuSelectionManager msm = 88 MenuSelectionManager.defaultManager(); 89 MenuElement[] path = msm.getSelectedPath(); 90 if (path.length > 0 && ! (path[0] instanceof ComboPopup)) { 91 msm.clearSelectedPath(); 92 menuCanceledOnPress = true; 93 ev.consume(); 94 } else if(path.length > 0) { // We are in ComboBox 95 menuCanceledOnPress = false; 96 WindowsLookAndFeel.setMnemonicHidden(false); 97 WindowsGraphicsUtils.repaintMnemonicsInWindow(winAncestor); 98 ev.consume(); 99 } else { 100 menuCanceledOnPress = false; 101 WindowsLookAndFeel.setMnemonicHidden(false); 102 WindowsGraphicsUtils.repaintMnemonicsInWindow(winAncestor); 103 JMenuBar mbar = root != null ? root.getJMenuBar() : null; 104 if(mbar == null && winAncestor instanceof JFrame) { 105 mbar = ((JFrame)winAncestor).getJMenuBar(); 106 } 107 JMenu menu = mbar != null ? mbar.getMenu(0) : null; 108 if(menu != null) { 109 ev.consume(); 110 } 111 } 112 } 113 114 void altReleased(KeyEvent ev) { 115 if (menuCanceledOnPress) { 116 WindowsLookAndFeel.setMnemonicHidden(true); 117 WindowsGraphicsUtils.repaintMnemonicsInWindow(winAncestor); 118 return; 119 } 120 121 MenuSelectionManager msm = 122 MenuSelectionManager.defaultManager(); 123 if (msm.getSelectedPath().length == 0) { 124 // if no menu is active, we try activating the menubar 125 126 JMenuBar mbar = root != null ? root.getJMenuBar() : null; 127 if(mbar == null && winAncestor instanceof JFrame) { 128 mbar = ((JFrame)winAncestor).getJMenuBar(); 129 } 130 JMenu menu = mbar != null ? mbar.getMenu(0) : null; 131 132 // It might happen that the altRelease event is processed 133 // with a reasonable delay since it has been generated. 134 // Here we check the last deactivation time of the containing 135 // window. If this time appears to be greater than the altRelease 136 // event time the event is skipped to avoid unexpected menu 137 // activation. See 7121442. 138 // Also we must ensure that original source of key event belongs 139 // to the same window object as winAncestor. See 8001633. 140 boolean skip = false; 141 Toolkit tk = Toolkit.getDefaultToolkit(); 142 if (tk instanceof SunToolkit) { 143 Component originalSource = AWTAccessor.getKeyEventAccessor() 144 .getOriginalSource(ev); 145 skip = SunToolkit.getContainingWindow(originalSource) != winAncestor || 146 ev.getWhen() <= ((SunToolkit) tk).getWindowDeactivationTime(winAncestor); 147 } 148 149 if (menu != null && !skip) { 150 MenuElement[] path = new MenuElement[2]; 151 path[0] = mbar; 152 path[1] = menu; 153 msm.setSelectedPath(path); 154 } else if(!WindowsLookAndFeel.isMnemonicHidden()) { 155 WindowsLookAndFeel.setMnemonicHidden(true); 156 WindowsGraphicsUtils.repaintMnemonicsInWindow(winAncestor); 157 } 158 } else { 159 if((msm.getSelectedPath())[0] instanceof ComboPopup) { 160 WindowsLookAndFeel.setMnemonicHidden(true); 161 WindowsGraphicsUtils.repaintMnemonicsInWindow(winAncestor); 162 } 163 } 164 165 } 166 167 public boolean postProcessKeyEvent(KeyEvent ev) { 168 if(ev.isConsumed()) { 169 // do not manage consumed event 170 return false; 171 } 172 if (ev.getKeyCode() == KeyEvent.VK_ALT) { 173 root = SwingUtilities.getRootPane(ev.getComponent()); 174 winAncestor = (root == null ? null : 175 SwingUtilities.getWindowAncestor(root)); 176 177 if (ev.getID() == KeyEvent.KEY_PRESSED) { 178 if (!altKeyPressed) { 179 altPressed(ev); 180 } 181 altKeyPressed = true; 182 return true; 183 } else if (ev.getID() == KeyEvent.KEY_RELEASED) { 184 if (altKeyPressed) { 185 altReleased(ev); 186 } else { 187 MenuSelectionManager msm = 188 MenuSelectionManager.defaultManager(); 189 MenuElement[] path = msm.getSelectedPath(); 190 if (path.length <= 0) { 191 WindowsLookAndFeel.setMnemonicHidden(true); 192 WindowsGraphicsUtils.repaintMnemonicsInWindow(winAncestor); 193 } 194 } 195 altKeyPressed = false; 196 } 197 root = null; 198 winAncestor = null; 199 } else { 200 if (WindowsLookAndFeel.isMnemonicHidden() && ev.isAltDown()) { 201 WindowsLookAndFeel.setMnemonicHidden(false); 202 WindowsGraphicsUtils.repaintMnemonicsInWindow(winAncestor); 203 } 204 altKeyPressed = false; 205 } 206 return false; 207 } 208 } 209 }