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

Last change on this file since 7829 was 7005, checked in by Don-vip, 10 years ago

see #8465 - use diamond operator where applicable

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