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

Last change on this file since 5299 was 5018, checked in by akks, 12 years ago

fix "Shortcut redefinition" warnings after MapFrame reinitialization - see #7424 (core part)

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