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

Last change on this file since 12682 was 12639, checked in by Don-vip, 7 years ago

see #15182 - deprecate shortcut handling and mapframe listener methods in Main. Replacement: same methods in gui.MainApplication

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