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

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

sonar - Immutable Field

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