From c11a6d1118df744f751bab2ac2d62ba0202e881f Mon Sep 17 00:00:00 2001 From: ddehaven Date: Tue, 15 Nov 2016 14:41:02 -0800 Subject: [PATCH] 7172652: With JDK 1.7 text field does not obtain focus when using mnemonic Alt/Key combin Reviewed-by: alexsch, azvegint Contributed-by: vivi.an@oracle.com --- .../javax/swing/plaf/basic/BasicLabelUI.java | 158 +++++++++++++--- .../plaf/basic/BasicLabelUI/bug7172652.java | 172 ++++++++++++++++++ 2 files changed, 305 insertions(+), 25 deletions(-) create mode 100644 test/javax/swing/plaf/basic/BasicLabelUI/bug7172652.java diff --git a/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java b/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java index 9c31265d1..8e99c38fa 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,6 +80,14 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener * This method is here so that a subclass could do Label specific * layout and to shorten the method name a little. * + * @param label an instance of {@code JLabel} + * @param fontMetrics a font metrics + * @param text a text + * @param icon an icon + * @param viewR a bounding rectangle to lay out label + * @param iconR a bounding rectangle to lay out icon + * @param textR a bounding rectangle to lay out text + * @return a possibly clipped version of the compound labels string * @see SwingUtilities#layoutCompoundLabel */ protected String layoutCL( @@ -109,6 +117,11 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener /** * Paint clippedText at textX, textY with the labels foreground color. * + * @param l an instance of {@code JLabel} + * @param g an instance of {@code Graphics} + * @param s a text + * @param textX an X coordinate + * @param textY an Y coordinate * @see #paint * @see #paintDisabledText */ @@ -125,6 +138,11 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener * Paint clippedText at textX, textY with background.lighter() and then * shifted down and to the right by one pixel with background.darker(). * + * @param l an instance of {@code JLabel} + * @param g an instance of {@code Graphics} + * @param s a text + * @param textX an X coordinate + * @param textY an Y coordinate * @see #paint * @see #paintEnabledText */ @@ -329,26 +347,46 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener public void uninstallUI(JComponent c) { - uninstallDefaults((JLabel)c); - uninstallComponents((JLabel)c); - uninstallListeners((JLabel)c); - uninstallKeyboardActions((JLabel)c); + uninstallDefaults((JLabel) c); + uninstallComponents((JLabel) c); + uninstallListeners((JLabel) c); + uninstallKeyboardActions((JLabel) c); } - protected void installDefaults(JLabel c){ - LookAndFeel.installColorsAndFont(c, "Label.background", "Label.foreground", "Label.font"); - LookAndFeel.installProperty(c, "opaque", Boolean.FALSE); - } + /** + * Installs default properties. + * + * @param c an instance of {@code JLabel} + */ + protected void installDefaults(JLabel c){ + LookAndFeel.installColorsAndFont(c, "Label.background", "Label.foreground", "Label.font"); + LookAndFeel.installProperty(c, "opaque", Boolean.FALSE); + } + /** + * Registers listeners. + * + * @param c an instance of {@code JLabel} + */ protected void installListeners(JLabel c){ c.addPropertyChangeListener(this); } + /** + * Registers components. + * + * @param c an instance of {@code JLabel} + */ protected void installComponents(JLabel c){ BasicHTML.updateRenderer(c, c.getText()); c.setInheritsPopupMenu(true); } + /** + * Registers keyboard actions. + * + * @param l an instance of {@code JLabel} + */ protected void installKeyboardActions(JLabel l) { int dka = l.getDisplayedMnemonic(); Component lf = l.getLabelFor(); @@ -374,17 +412,37 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener } } + /** + * Uninstalls default properties. + * + * @param c an instance of {@code JLabel} + */ protected void uninstallDefaults(JLabel c){ } + /** + * Unregisters listeners. + * + * @param c an instance of {@code JLabel} + */ protected void uninstallListeners(JLabel c){ c.removePropertyChangeListener(this); } + /** + * Unregisters components. + * + * @param c an instance of {@code JLabel} + */ protected void uninstallComponents(JLabel c){ BasicHTML.updateRenderer(c, ""); } + /** + * Unregisters keyboard actions. + * + * @param c an instance of {@code JLabel} + */ protected void uninstallKeyboardActions(JLabel c) { SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, null); SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_IN_FOCUSED_WINDOW, @@ -392,6 +450,12 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener SwingUtilities.replaceUIActionMap(c, null); } + /** + * Returns an instance of {@code BasicLabelUI}. + * + * @param c a component + * @return an instance of {@code BasicLabelUI} + */ public static ComponentUI createUI(JComponent c) { if (System.getSecurityManager() != null) { AppContext appContext = AppContext.getAppContext(); @@ -440,7 +504,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener doPress(label); } else if (key == RELEASE) { - doRelease(label); + doRelease(label, e.getActionCommand() != null); } } @@ -453,33 +517,77 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener SwingUtilities.replaceUIInputMap(label, JComponent.WHEN_FOCUSED, inputMap); } int dka = label.getDisplayedMnemonic(); - inputMap.put(KeyStroke.getKeyStroke(dka, BasicLookAndFeel.getFocusAcceleratorKeyMask(), true), RELEASE); + putOnRelease(inputMap, dka, BasicLookAndFeel + .getFocusAcceleratorKeyMask()); // Need this when the sticky keys are enabled - inputMap.put(KeyStroke.getKeyStroke(dka, 0, true), RELEASE); + putOnRelease(inputMap, dka, 0); // Need this if ALT is released before the accelerator - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ALT, 0, true), RELEASE); + putOnRelease(inputMap, KeyEvent.VK_ALT, 0); label.requestFocus(); } } - private void doRelease(JLabel label) { + private void doRelease(JLabel label, boolean isCommand) { Component labelFor = label.getLabelFor(); if (labelFor != null && labelFor.isEnabled()) { - InputMap inputMap = SwingUtilities.getUIInputMap(label, JComponent.WHEN_FOCUSED); - if (inputMap != null) { - // inputMap should never be null. + if (label.hasFocus()) { + InputMap inputMap = SwingUtilities.getUIInputMap(label, + JComponent.WHEN_FOCUSED); + if (inputMap != null) { + // inputMap should never be null. + int dka = label.getDisplayedMnemonic(); + removeOnRelease(inputMap, dka, BasicLookAndFeel + .getFocusAcceleratorKeyMask()); + removeOnRelease(inputMap, dka, 0); + removeOnRelease(inputMap, KeyEvent.VK_ALT, 0); + } + inputMap = SwingUtilities.getUIInputMap(label, + JComponent.WHEN_IN_FOCUSED_WINDOW); + if (inputMap == null) { + inputMap = new InputMapUIResource(); + SwingUtilities.replaceUIInputMap(label, + JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap); + } int dka = label.getDisplayedMnemonic(); - inputMap.remove(KeyStroke.getKeyStroke(dka, BasicLookAndFeel.getFocusAcceleratorKeyMask(), true)); - inputMap.remove(KeyStroke.getKeyStroke(dka, 0, true)); - inputMap.remove(KeyStroke.getKeyStroke(KeyEvent.VK_ALT, 0, true)); - } - if (labelFor instanceof Container && - ((Container) labelFor).isFocusCycleRoot()) { - labelFor.requestFocus(); + if (isCommand) { + putOnRelease(inputMap, KeyEvent.VK_ALT, 0); + } else { + putOnRelease(inputMap, dka, BasicLookAndFeel + .getFocusAcceleratorKeyMask()); + // Need this when the sticky keys are enabled + putOnRelease(inputMap, dka, 0); + } + if (labelFor instanceof Container && + ((Container) labelFor).isFocusCycleRoot()) { + labelFor.requestFocus(); + } else { + SwingUtilities2.compositeRequestFocus(labelFor); + } } else { - SwingUtilities2.compositeRequestFocus(labelFor); + InputMap inputMap = SwingUtilities.getUIInputMap(label, + JComponent.WHEN_IN_FOCUSED_WINDOW); + int dka = label.getDisplayedMnemonic(); + if (inputMap != null) { + if (isCommand) { + removeOnRelease(inputMap, dka, BasicLookAndFeel + .getFocusAcceleratorKeyMask()); + removeOnRelease(inputMap, dka, 0); + } else { + removeOnRelease(inputMap, KeyEvent.VK_ALT, 0); + } + } } } } + + private void putOnRelease(InputMap inputMap, int keyCode, int modifiers) { + inputMap.put(KeyStroke.getKeyStroke(keyCode, modifiers, true), + RELEASE); + } + + private void removeOnRelease(InputMap inputMap, int keyCode, int modifiers) { + inputMap.remove(KeyStroke.getKeyStroke(keyCode, modifiers, true)); + } + } } diff --git a/test/javax/swing/plaf/basic/BasicLabelUI/bug7172652.java b/test/javax/swing/plaf/basic/BasicLabelUI/bug7172652.java new file mode 100644 index 000000000..8a06c48e9 --- /dev/null +++ b/test/javax/swing/plaf/basic/BasicLabelUI/bug7172652.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 7172652 + @summary With JDK 1.7 text field does not obtain focus when using mnemonic Alt/Key combin + @author Semyon Sadetsky + @library /lib/testlibrary + @build jdk.testlibrary.OSInfo + @run main bug7172652 + */ + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.KeyEvent; +import jdk.testlibrary.OSInfo; + +public class bug7172652 { + + private static JMenu menu; + private static JFrame frame; + private static Boolean selected; + + public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) { + System.out.println("ok"); + return; + } + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + setup(); + } + }); + + test(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + } + + private static void test() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + menu.getModel().addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + selected = menu.isSelected(); + } + }); + } + }); + + Robot robot = new Robot(); + robot.setAutoDelay(200); + + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_ALT); + + robot.waitForIdle(); + if( selected != null ) { + throw new RuntimeException("Menu is notified selected= " + selected); + } + + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_ALT); + if( selected != null ) { + throw new RuntimeException("Menu is notified selected= " + selected); + } + + robot.waitForIdle(); + + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_ALT); + if( selected != null ) { + throw new RuntimeException("Menu is notified selected= " + selected); + } + + robot.waitForIdle(); + + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_ALT); + if( selected != null ) { + throw new RuntimeException("Menu is notified selected= " + selected); + } + + robot.waitForIdle(); + + System.out.printf("ok"); + } + + private static void setup() { + JLabel firstLbl = new JLabel("First name"); + JLabel lastLbl = new JLabel("Last name"); + JMenuBar menuBar = new JMenuBar(); + + JTextField firstTxtFld = new JTextField(20); + JTextField lastTxtFld = new JTextField(20); + JDesktopPane desktopPane = new JDesktopPane(); + JInternalFrame iframe = new JInternalFrame("A frame", true, true, true, true); + + // Set an initial size + iframe.setSize(200, 220); + + // By default, internal frames are not visible; make it visible + iframe.setVisible(true); + + JPanel pane = new JPanel(); + pane.setLayout(new FlowLayout()); + + pane.add(firstLbl); + pane.add(firstTxtFld); + pane.add(lastLbl); + pane.add(lastTxtFld); + + firstLbl.setLabelFor(firstTxtFld); + firstLbl.setDisplayedMnemonic('F'); + + lastLbl.setLabelFor(lastTxtFld); + lastLbl.setDisplayedMnemonic('L'); + + iframe.getContentPane().add(pane); + iframe.setJMenuBar(menuBar); + menu = new JMenu("FirstMenu"); + //m.setMnemonic('i'); + menuBar.add(menu); + desktopPane.add(iframe); + + frame = new JFrame(); + frame.setUndecorated(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().add(desktopPane); + frame.setSize(300, 300); + frame.setVisible(true); + } + +} -- GitLab