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

Last change on this file since 4753 was 4753, checked in by jttt, 12 years ago

Run in EDT

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