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

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

Use different way to center popup menu title to prevent blank menu on Windows 7, add shortcuts to enable/hiding of filters (see #5515)

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