001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.tools; 003 004import java.awt.event.InputEvent; 005import java.awt.event.KeyEvent; 006import java.util.Optional; 007 008import javax.swing.Action; 009import javax.swing.InputMap; 010import javax.swing.JButton; 011import javax.swing.JComponent; 012import javax.swing.KeyStroke; 013import javax.swing.SwingUtilities; 014 015/** 016 * Tools to work with Swing InputMap. 017 * @since 5200 018 */ 019public final class InputMapUtils { 020 021 private InputMapUtils() { 022 // Hide default constructor for utils classes 023 } 024 025 /** 026 * Unassign Ctrl-Shift/Alt-Shift Up/Down from the given component 027 * to allow global JOSM shortcuts to work in this component. 028 * @param cmp The Swing component 029 * @param condition one of the following values: 030 * <ul> 031 * <li>JComponent.FOCUS_INPUTMAP_CREATED 032 * <li>JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 033 * <li>JComponent.WHEN_IN_FOCUSED_WINDOW 034 * </ul> 035 */ 036 public static void unassignCtrlShiftUpDown(JComponent cmp, int condition) { 037 InputMap inputMap = SwingUtilities.getUIInputMap(cmp, condition); 038 inputMap.remove(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)); 039 inputMap.remove(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)); 040 inputMap.remove(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)); 041 inputMap.remove(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)); 042 SwingUtilities.replaceUIInputMap(cmp, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap); 043 } 044 045 /** 046 * Unassign PageUp/PageDown from the given component 047 * to allow global JOSM shortcuts to work in this component. 048 * @param cmp The Swing component 049 * @param condition one of the following values: 050 * <ul> 051 * <li>JComponent.FOCUS_INPUTMAP_CREATED 052 * <li>JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 053 * <li>JComponent.WHEN_IN_FOCUSED_WINDOW 054 * </ul> 055 * @since 6557 056 */ 057 public static void unassignPageUpDown(JComponent cmp, int condition) { 058 InputMap inputMap = SwingUtilities.getUIInputMap(cmp, condition); 059 inputMap.remove(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0)); 060 inputMap.remove(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0)); 061 SwingUtilities.replaceUIInputMap(cmp, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap); 062 } 063 064 /** 065 * Enable activating button on Enter (which is replaced with spacebar for certain Look-And-Feels). 066 * @param b Button 067 */ 068 public static void enableEnter(JButton b) { 069 b.setFocusable(true); 070 addEnterAction(b, b.getAction()); 071 } 072 073 /** 074 * Add an action activated with Enter key on a component. 075 * @param c The Swing component 076 * @param a action activated with Enter key 077 * @see JComponent#WHEN_FOCUSED 078 */ 079 public static void addEnterAction(JComponent c, Action a) { 080 addEnterAction(c, a, JComponent.WHEN_FOCUSED); 081 } 082 083 /** 084 * Add an action activated with Enter key on a component or its children. 085 * @param c The Swing component 086 * @param a action activated with Enter key 087 * @see JComponent#WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 088 * @since 10790 089 */ 090 public static void addEnterActionWhenAncestor(JComponent c, Action a) { 091 addEnterAction(c, a, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 092 } 093 094 private static void addEnterAction(JComponent c, Action a, int condition) { 095 c.getActionMap().put("enter", a); 096 c.getInputMap(condition).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "enter"); 097 } 098 099 /** 100 * Add an action activated with Spacebar key on a component. 101 * @param c The Swing component 102 * @param a action activated with Spacebar key 103 */ 104 public static void addSpacebarAction(JComponent c, Action a) { 105 c.getActionMap().put("spacebar", a); 106 c.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "spacebar"); 107 } 108 109 /** 110 * Add an action activated with ESCAPE key on a component or its children. 111 * @param c The Swing component 112 * @param a action activated with ESCAPE key 113 * @see JComponent#WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 114 * @since 10791 115 */ 116 public static void addEscapeAction(JComponent c, Action a) { 117 c.getActionMap().put("escape", a); 118 c.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape"); 119 } 120 121 /** 122 * Add an action activated with Ctrl+Enter key on a component. 123 * @param c The Swing component 124 * @param a action activated with Ctrl+Enter key 125 * @see JComponent#WHEN_IN_FOCUSED_WINDOW 126 */ 127 public static void addCtrlEnterAction(JComponent c, Action a) { 128 final KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK); 129 c.getActionMap().put("ctrl_enter", a); 130 c.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(stroke, "ctrl_enter"); 131 Optional.ofNullable(a) 132 .map(x -> x.getValue(Action.SHORT_DESCRIPTION)) 133 .map(String::valueOf) 134 .ifPresent(text -> Shortcut.setTooltip(a, text, stroke)); 135 } 136}