source: josm/trunk/src/org/openstreetmap/josm/tools/MultikeyActionsHandler.java@ 10991

Last change on this file since 10991 was 10616, checked in by Don-vip, 8 years ago

see #11390 - sonar - squid:S1604 - Java 8: Anonymous inner classes containing only one method should become lambdas

  • Property svn:eol-style set to native
File size: 8.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.KeyEventDispatcher;
7import java.awt.KeyboardFocusManager;
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.util.HashMap;
11import java.util.Map;
12import java.util.Timer;
13import java.util.TimerTask;
14
15import javax.swing.AbstractAction;
16import javax.swing.Action;
17import javax.swing.JMenuItem;
18import javax.swing.JPanel;
19import javax.swing.JPopupMenu;
20import javax.swing.KeyStroke;
21import javax.swing.SwingUtilities;
22import javax.swing.event.PopupMenuEvent;
23import javax.swing.event.PopupMenuListener;
24
25import org.openstreetmap.josm.Main;
26import org.openstreetmap.josm.tools.MultikeyShortcutAction.MultikeyInfo;
27
28public final class MultikeyActionsHandler {
29
30 private static final long DIALOG_DELAY = 1000;
31 private static final String STATUS_BAR_ID = "multikeyShortcut";
32
33 private final Map<MultikeyShortcutAction, MyAction> myActions = new HashMap<>();
34
35 private static final class ShowLayersPopupWorker implements Runnable {
36 private final MyAction action;
37
38 private ShowLayersPopupWorker(MyAction action) {
39 this.action = action;
40 }
41
42 @Override
43 public void run() {
44 JPopupMenu layers = new JPopupMenu();
45
46 JMenuItem lbTitle = new JMenuItem((String) action.action.getValue(Action.SHORT_DESCRIPTION));
47 lbTitle.setEnabled(false);
48 JPanel pnTitle = new JPanel();
49 pnTitle.add(lbTitle);
50 layers.add(pnTitle);
51
52 char repeatKey = (char) action.shortcut.getKeyStroke().getKeyCode();
53 boolean repeatKeyUsed = false;
54
55 for (final MultikeyInfo info: action.action.getMultikeyCombinations()) {
56
57 if (info.getShortcut() == repeatKey) {
58 repeatKeyUsed = true;
59 }
60
61 JMenuItem item = new JMenuItem(formatMenuText(action.shortcut.getKeyStroke(),
62 String.valueOf(info.getShortcut()), info.getDescription()));
63 item.setMnemonic(info.getShortcut());
64 item.addActionListener(e -> action.action.executeMultikeyAction(info.getIndex(), false));
65 layers.add(item);
66 }
67
68 if (!repeatKeyUsed) {
69 MultikeyInfo lastLayer = action.action.getLastMultikeyAction();
70 if (lastLayer != null) {
71 JMenuItem repeateItem = new JMenuItem(formatMenuText(action.shortcut.getKeyStroke(),
72 KeyEvent.getKeyText(action.shortcut.getKeyStroke().getKeyCode()),
73 "Repeat " + lastLayer.getDescription()));
74 repeateItem.setMnemonic(action.shortcut.getKeyStroke().getKeyCode());
75 repeateItem.addActionListener(e -> action.action.executeMultikeyAction(-1, true));
76 layers.add(repeateItem);
77 }
78 }
79 layers.addPopupMenuListener(new PopupMenuListener() {
80
81 @Override
82 public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
83 // Do nothing
84 }
85
86 @Override
87 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
88 Main.map.statusLine.resetHelpText(STATUS_BAR_ID);
89 }
90
91 @Override
92 public void popupMenuCanceled(PopupMenuEvent e) {
93 // Do nothing
94 }
95 });
96
97 layers.show(Main.parent, Integer.MAX_VALUE, Integer.MAX_VALUE);
98 layers.setLocation(Main.parent.getX() + Main.parent.getWidth() - layers.getWidth(),
99 Main.parent.getY() + Main.parent.getHeight() - layers.getHeight());
100 }
101 }
102
103 private class MyKeyEventDispatcher implements KeyEventDispatcher {
104 @Override
105 public boolean dispatchKeyEvent(KeyEvent e) {
106
107 if (e.getWhen() == lastTimestamp)
108 return false;
109
110 if (lastAction != null && e.getID() == KeyEvent.KEY_PRESSED) {
111 int index = getIndex(e.getKeyCode());
112 if (index >= 0) {
113 lastAction.action.executeMultikeyAction(index, e.getKeyCode() == lastAction.shortcut.getKeyStroke().getKeyCode());
114 }
115 lastAction = null;
116 Main.map.statusLine.resetHelpText(STATUS_BAR_ID);
117 return true;
118 }
119 return false;
120 }
121
122 private int getIndex(int lastKey) {
123 if (lastKey >= KeyEvent.VK_1 && lastKey <= KeyEvent.VK_9)
124 return lastKey - KeyEvent.VK_1;
125 else if (lastKey == KeyEvent.VK_0)
126 return 9;
127 else if (lastKey >= KeyEvent.VK_A && lastKey <= KeyEvent.VK_Z)
128 return lastKey - KeyEvent.VK_A + 10;
129 else
130 return -1;
131 }
132 }
133
134 private class MyAction extends AbstractAction {
135
136 private final transient MultikeyShortcutAction action;
137 private final transient Shortcut shortcut;
138
139 MyAction(MultikeyShortcutAction action) {
140 this.action = action;
141 this.shortcut = action.getMultikeyShortcut();
142 }
143
144 @Override
145 public void actionPerformed(ActionEvent e) {
146 lastTimestamp = e.getWhen();
147 lastAction = this;
148 timer.schedule(new MyTimerTask(lastTimestamp, lastAction), DIALOG_DELAY);
149 Main.map.statusLine.setHelpText(STATUS_BAR_ID, tr("{0}... [please type its number]", (String) action.getValue(SHORT_DESCRIPTION)));
150 }
151
152 @Override
153 public String toString() {
154 return "MultikeyAction" + action;
155 }
156 }
157
158 private class MyTimerTask extends TimerTask {
159 private final long lastTimestamp;
160 private final MyAction lastAction;
161
162 MyTimerTask(long lastTimestamp, MyAction lastAction) {
163 this.lastTimestamp = lastTimestamp;
164 this.lastAction = lastAction;
165 }
166
167 @Override
168 public void run() {
169 if (lastTimestamp == MultikeyActionsHandler.this.lastTimestamp &&
170 lastAction == MultikeyActionsHandler.this.lastAction) {
171 SwingUtilities.invokeLater(new ShowLayersPopupWorker(lastAction));
172 MultikeyActionsHandler.this.lastAction = null;
173 }
174 }
175 }
176
177 private long lastTimestamp;
178 private MyAction lastAction;
179 private final Timer timer;
180
181 private MultikeyActionsHandler() {
182 KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new MyKeyEventDispatcher());
183 timer = new Timer();
184 }
185
186 private static MultikeyActionsHandler instance;
187
188 /**
189 * Replies the unique instance of this class.
190 * @return The unique instance of this class
191 */
192 public static synchronized MultikeyActionsHandler getInstance() {
193 if (instance == null) {
194 instance = new MultikeyActionsHandler();
195 }
196 return instance;
197 }
198
199 private static String formatMenuText(KeyStroke keyStroke, String index, String description) {
200 String shortcutText = KeyEvent.getKeyModifiersText(keyStroke.getModifiers()) + '+'
201 + KeyEvent.getKeyText(keyStroke.getKeyCode()) + ',' + index;
202
203 return "<html><i>" + shortcutText + "</i>&nbsp;&nbsp;&nbsp;&nbsp;" + description;
204 }
205
206 /**
207 * Registers an action and its shortcut
208 * @param action The action to add
209 */
210 public void addAction(MultikeyShortcutAction action) {
211 if (action.getMultikeyShortcut() != null) {
212 MyAction myAction = new MyAction(action);
213 myActions.put(action, myAction);
214 Main.registerActionShortcut(myAction, myAction.shortcut);
215 }
216 }
217
218 /**
219 * Unregisters an action and its shortcut completely
220 * @param action The action to remove
221 */
222 public void removeAction(MultikeyShortcutAction action) {
223 MyAction a = myActions.get(action);
224 if (a != null) {
225 Main.unregisterActionShortcut(a, a.shortcut);
226 myActions.remove(action);
227 }
228 }
229}
Note: See TracBrowser for help on using the repository browser.