author | weijun |
Thu, 11 Dec 2014 15:19:12 +0800 | |
changeset 28228 | be83f404724d |
parent 25859 | 3317bb8137f4 |
child 30934 | b9fb91f448aa |
permissions | -rw-r--r-- |
2 | 1 |
/* |
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
2 |
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. |
2 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
||
26 |
package javax.swing.plaf.basic; |
|
27 |
||
28 |
import javax.swing.*; |
|
29 |
import javax.swing.event.*; |
|
30 |
import javax.swing.plaf.*; |
|
31 |
import javax.swing.plaf.basic.*; |
|
32 |
import javax.swing.border.*; |
|
33 |
||
34 |
import java.applet.Applet; |
|
35 |
||
36 |
import java.awt.Component; |
|
37 |
import java.awt.Container; |
|
38 |
import java.awt.Dimension; |
|
39 |
import java.awt.KeyboardFocusManager; |
|
40 |
import java.awt.Window; |
|
41 |
import java.awt.event.*; |
|
42 |
import java.awt.AWTEvent; |
|
43 |
import java.awt.Toolkit; |
|
44 |
||
45 |
import java.beans.PropertyChangeListener; |
|
46 |
import java.beans.PropertyChangeEvent; |
|
47 |
||
48 |
import java.util.*; |
|
49 |
||
50 |
import sun.swing.DefaultLookup; |
|
51 |
import sun.swing.UIAction; |
|
52 |
||
53 |
import sun.awt.AppContext; |
|
54 |
||
55 |
/** |
|
20169 | 56 |
* A Windows L&F implementation of PopupMenuUI. This implementation |
2 | 57 |
* is a "combined" view/controller. |
58 |
* |
|
59 |
* @author Georges Saab |
|
60 |
* @author David Karlton |
|
61 |
* @author Arnaud Weber |
|
62 |
*/ |
|
63 |
public class BasicPopupMenuUI extends PopupMenuUI { |
|
64 |
static final StringBuilder MOUSE_GRABBER_KEY = new StringBuilder( |
|
65 |
"javax.swing.plaf.basic.BasicPopupMenuUI.MouseGrabber"); |
|
66 |
static final StringBuilder MENU_KEYBOARD_HELPER_KEY = new StringBuilder( |
|
67 |
"javax.swing.plaf.basic.BasicPopupMenuUI.MenuKeyboardHelper"); |
|
68 |
||
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
69 |
/** |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
70 |
* The instance of {@code JPopupMenu}. |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
71 |
*/ |
2 | 72 |
protected JPopupMenu popupMenu = null; |
73 |
private transient PopupMenuListener popupMenuListener = null; |
|
74 |
private MenuKeyListener menuKeyListener = null; |
|
75 |
||
76 |
private static boolean checkedUnpostPopup; |
|
77 |
private static boolean unpostPopup; |
|
78 |
||
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
79 |
/** |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
80 |
* Constructs a new instance of {@code BasicPopupMenuUI}. |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
81 |
* |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
82 |
* @param x a component |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
83 |
* @return a new instance of {@code BasicPopupMenuUI} |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
84 |
*/ |
2 | 85 |
public static ComponentUI createUI(JComponent x) { |
86 |
return new BasicPopupMenuUI(); |
|
87 |
} |
|
88 |
||
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
89 |
/** |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
90 |
* Constructs a new instance of {@code BasicPopupMenuUI}. |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
91 |
*/ |
2 | 92 |
public BasicPopupMenuUI() { |
93 |
BasicLookAndFeel.needsEventHelper = true; |
|
94 |
LookAndFeel laf = UIManager.getLookAndFeel(); |
|
95 |
if (laf instanceof BasicLookAndFeel) { |
|
96 |
((BasicLookAndFeel)laf).installAWTEventListener(); |
|
97 |
} |
|
98 |
} |
|
99 |
||
100 |
public void installUI(JComponent c) { |
|
101 |
popupMenu = (JPopupMenu) c; |
|
102 |
||
103 |
installDefaults(); |
|
104 |
installListeners(); |
|
105 |
installKeyboardActions(); |
|
106 |
} |
|
107 |
||
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
108 |
/** |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
109 |
* Installs default properties. |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
110 |
*/ |
2 | 111 |
public void installDefaults() { |
112 |
if (popupMenu.getLayout() == null || |
|
113 |
popupMenu.getLayout() instanceof UIResource) |
|
114 |
popupMenu.setLayout(new DefaultMenuLayout(popupMenu, BoxLayout.Y_AXIS)); |
|
115 |
||
116 |
LookAndFeel.installProperty(popupMenu, "opaque", Boolean.TRUE); |
|
117 |
LookAndFeel.installBorder(popupMenu, "PopupMenu.border"); |
|
118 |
LookAndFeel.installColorsAndFont(popupMenu, |
|
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
119 |
"PopupMenu.background", |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
120 |
"PopupMenu.foreground", |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
121 |
"PopupMenu.font"); |
2 | 122 |
} |
123 |
||
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
124 |
/** |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
125 |
* Registers listeners. |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
126 |
*/ |
2 | 127 |
protected void installListeners() { |
128 |
if (popupMenuListener == null) { |
|
129 |
popupMenuListener = new BasicPopupMenuListener(); |
|
130 |
} |
|
131 |
popupMenu.addPopupMenuListener(popupMenuListener); |
|
132 |
||
133 |
if (menuKeyListener == null) { |
|
134 |
menuKeyListener = new BasicMenuKeyListener(); |
|
135 |
} |
|
136 |
popupMenu.addMenuKeyListener(menuKeyListener); |
|
137 |
||
138 |
AppContext context = AppContext.getAppContext(); |
|
139 |
synchronized (MOUSE_GRABBER_KEY) { |
|
140 |
MouseGrabber mouseGrabber = (MouseGrabber)context.get( |
|
141 |
MOUSE_GRABBER_KEY); |
|
142 |
if (mouseGrabber == null) { |
|
143 |
mouseGrabber = new MouseGrabber(); |
|
144 |
context.put(MOUSE_GRABBER_KEY, mouseGrabber); |
|
145 |
} |
|
146 |
} |
|
147 |
synchronized (MENU_KEYBOARD_HELPER_KEY) { |
|
148 |
MenuKeyboardHelper helper = |
|
149 |
(MenuKeyboardHelper)context.get(MENU_KEYBOARD_HELPER_KEY); |
|
150 |
if (helper == null) { |
|
151 |
helper = new MenuKeyboardHelper(); |
|
152 |
context.put(MENU_KEYBOARD_HELPER_KEY, helper); |
|
153 |
MenuSelectionManager msm = MenuSelectionManager.defaultManager(); |
|
154 |
msm.addChangeListener(helper); |
|
155 |
} |
|
156 |
} |
|
157 |
} |
|
158 |
||
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
159 |
/** |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
160 |
* Registers keyboard actions. |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
161 |
*/ |
2 | 162 |
protected void installKeyboardActions() { |
163 |
} |
|
164 |
||
165 |
static InputMap getInputMap(JPopupMenu popup, JComponent c) { |
|
166 |
InputMap windowInputMap = null; |
|
167 |
Object[] bindings = (Object[])UIManager.get("PopupMenu.selectedWindowInputMapBindings"); |
|
168 |
if (bindings != null) { |
|
169 |
windowInputMap = LookAndFeel.makeComponentInputMap(c, bindings); |
|
170 |
if (!popup.getComponentOrientation().isLeftToRight()) { |
|
171 |
Object[] km = (Object[])UIManager.get("PopupMenu.selectedWindowInputMapBindings.RightToLeft"); |
|
172 |
if (km != null) { |
|
173 |
InputMap rightToLeftInputMap = LookAndFeel.makeComponentInputMap(c, km); |
|
174 |
rightToLeftInputMap.setParent(windowInputMap); |
|
175 |
windowInputMap = rightToLeftInputMap; |
|
176 |
} |
|
177 |
} |
|
178 |
} |
|
179 |
return windowInputMap; |
|
180 |
} |
|
181 |
||
182 |
static ActionMap getActionMap() { |
|
183 |
return LazyActionMap.getActionMap(BasicPopupMenuUI.class, |
|
184 |
"PopupMenu.actionMap"); |
|
185 |
} |
|
186 |
||
187 |
static void loadActionMap(LazyActionMap map) { |
|
188 |
map.put(new Actions(Actions.CANCEL)); |
|
189 |
map.put(new Actions(Actions.SELECT_NEXT)); |
|
190 |
map.put(new Actions(Actions.SELECT_PREVIOUS)); |
|
191 |
map.put(new Actions(Actions.SELECT_PARENT)); |
|
192 |
map.put(new Actions(Actions.SELECT_CHILD)); |
|
193 |
map.put(new Actions(Actions.RETURN)); |
|
194 |
BasicLookAndFeel.installAudioActionMap(map); |
|
195 |
} |
|
196 |
||
197 |
public void uninstallUI(JComponent c) { |
|
198 |
uninstallDefaults(); |
|
199 |
uninstallListeners(); |
|
200 |
uninstallKeyboardActions(); |
|
201 |
||
202 |
popupMenu = null; |
|
203 |
} |
|
204 |
||
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
205 |
/** |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
206 |
* Uninstalls default properties. |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
207 |
*/ |
2 | 208 |
protected void uninstallDefaults() { |
209 |
LookAndFeel.uninstallBorder(popupMenu); |
|
210 |
} |
|
211 |
||
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
212 |
/** |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
213 |
* Unregisters listeners. |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
214 |
*/ |
2 | 215 |
protected void uninstallListeners() { |
216 |
if (popupMenuListener != null) { |
|
217 |
popupMenu.removePopupMenuListener(popupMenuListener); |
|
218 |
} |
|
219 |
if (menuKeyListener != null) { |
|
220 |
popupMenu.removeMenuKeyListener(menuKeyListener); |
|
221 |
} |
|
222 |
} |
|
223 |
||
25761
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
224 |
/** |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
225 |
* Unregisters keyboard actions. |
c408b10ef757
8043968: Fix doclint warnings from javax.swing.plaf.basic package, 1 of 7
aeremeev
parents:
23010
diff
changeset
|
226 |
*/ |
2 | 227 |
protected void uninstallKeyboardActions() { |
228 |
SwingUtilities.replaceUIActionMap(popupMenu, null); |
|
229 |
SwingUtilities.replaceUIInputMap(popupMenu, |
|
230 |
JComponent.WHEN_IN_FOCUSED_WINDOW, null); |
|
231 |
} |
|
232 |
||
233 |
static MenuElement getFirstPopup() { |
|
234 |
MenuSelectionManager msm = MenuSelectionManager.defaultManager(); |
|
235 |
MenuElement[] p = msm.getSelectedPath(); |
|
236 |
MenuElement me = null; |
|
237 |
||
238 |
for(int i = 0 ; me == null && i < p.length ; i++) { |
|
239 |
if (p[i] instanceof JPopupMenu) |
|
240 |
me = p[i]; |
|
241 |
} |
|
242 |
||
243 |
return me; |
|
244 |
} |
|
245 |
||
246 |
static JPopupMenu getLastPopup() { |
|
247 |
MenuSelectionManager msm = MenuSelectionManager.defaultManager(); |
|
248 |
MenuElement[] p = msm.getSelectedPath(); |
|
249 |
JPopupMenu popup = null; |
|
250 |
||
251 |
for(int i = p.length - 1; popup == null && i >= 0; i--) { |
|
252 |
if (p[i] instanceof JPopupMenu) |
|
253 |
popup = (JPopupMenu)p[i]; |
|
254 |
} |
|
255 |
return popup; |
|
256 |
} |
|
257 |
||
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
258 |
static List<JPopupMenu> getPopups() { |
2 | 259 |
MenuSelectionManager msm = MenuSelectionManager.defaultManager(); |
260 |
MenuElement[] p = msm.getSelectedPath(); |
|
261 |
||
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
262 |
List<JPopupMenu> list = new ArrayList<JPopupMenu>(p.length); |
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
263 |
for (MenuElement element : p) { |
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
264 |
if (element instanceof JPopupMenu) { |
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
265 |
list.add((JPopupMenu) element); |
2 | 266 |
} |
267 |
} |
|
268 |
return list; |
|
269 |
} |
|
270 |
||
271 |
public boolean isPopupTrigger(MouseEvent e) { |
|
272 |
return ((e.getID()==MouseEvent.MOUSE_RELEASED) |
|
273 |
&& ((e.getModifiers() & MouseEvent.BUTTON3_MASK)!=0)); |
|
274 |
} |
|
275 |
||
276 |
private static boolean checkInvokerEqual(MenuElement present, MenuElement last) { |
|
277 |
Component invokerPresent = present.getComponent(); |
|
278 |
Component invokerLast = last.getComponent(); |
|
279 |
||
280 |
if (invokerPresent instanceof JPopupMenu) { |
|
281 |
invokerPresent = ((JPopupMenu)invokerPresent).getInvoker(); |
|
282 |
} |
|
283 |
if (invokerLast instanceof JPopupMenu) { |
|
284 |
invokerLast = ((JPopupMenu)invokerLast).getInvoker(); |
|
285 |
} |
|
286 |
return (invokerPresent == invokerLast); |
|
287 |
} |
|
288 |
||
289 |
||
290 |
/** |
|
291 |
* This Listener fires the Action that provides the correct auditory |
|
292 |
* feedback. |
|
293 |
* |
|
294 |
* @since 1.4 |
|
295 |
*/ |
|
296 |
private class BasicPopupMenuListener implements PopupMenuListener { |
|
297 |
public void popupMenuCanceled(PopupMenuEvent e) { |
|
298 |
} |
|
299 |
||
300 |
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { |
|
301 |
} |
|
302 |
||
303 |
public void popupMenuWillBecomeVisible(PopupMenuEvent e) { |
|
304 |
BasicLookAndFeel.playSound((JPopupMenu)e.getSource(), |
|
305 |
"PopupMenu.popupSound"); |
|
306 |
} |
|
307 |
} |
|
308 |
||
309 |
/** |
|
310 |
* Handles mnemonic for children JMenuItems. |
|
311 |
* @since 1.5 |
|
312 |
*/ |
|
313 |
private class BasicMenuKeyListener implements MenuKeyListener { |
|
314 |
MenuElement menuToOpen = null; |
|
315 |
||
316 |
public void menuKeyTyped(MenuKeyEvent e) { |
|
317 |
if (menuToOpen != null) { |
|
318 |
// we have a submenu to open |
|
319 |
JPopupMenu subpopup = ((JMenu)menuToOpen).getPopupMenu(); |
|
320 |
MenuElement subitem = findEnabledChild( |
|
321 |
subpopup.getSubElements(), -1, true); |
|
322 |
||
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
323 |
ArrayList<MenuElement> lst = new ArrayList<MenuElement>(Arrays.asList(e.getPath())); |
2 | 324 |
lst.add(menuToOpen); |
325 |
lst.add(subpopup); |
|
326 |
if (subitem != null) { |
|
327 |
lst.add(subitem); |
|
328 |
} |
|
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
329 |
MenuElement newPath[] = new MenuElement[0]; |
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
330 |
newPath = lst.toArray(newPath); |
2 | 331 |
MenuSelectionManager.defaultManager().setSelectedPath(newPath); |
332 |
e.consume(); |
|
333 |
} |
|
334 |
menuToOpen = null; |
|
335 |
} |
|
336 |
||
337 |
public void menuKeyPressed(MenuKeyEvent e) { |
|
338 |
char keyChar = e.getKeyChar(); |
|
339 |
||
340 |
// Handle the case for Escape or Enter... |
|
341 |
if (!Character.isLetterOrDigit(keyChar)) { |
|
342 |
return; |
|
343 |
} |
|
344 |
||
345 |
MenuSelectionManager manager = e.getMenuSelectionManager(); |
|
346 |
MenuElement path[] = e.getPath(); |
|
347 |
MenuElement items[] = popupMenu.getSubElements(); |
|
348 |
int currentIndex = -1; |
|
349 |
int matches = 0; |
|
350 |
int firstMatch = -1; |
|
351 |
int indexes[] = null; |
|
352 |
||
353 |
for (int j = 0; j < items.length; j++) { |
|
354 |
if (! (items[j] instanceof JMenuItem)) { |
|
355 |
continue; |
|
356 |
} |
|
357 |
JMenuItem item = (JMenuItem)items[j]; |
|
358 |
int mnemonic = item.getMnemonic(); |
|
359 |
if (item.isEnabled() && |
|
360 |
item.isVisible() && lower(keyChar) == lower(mnemonic)) { |
|
361 |
if (matches == 0) { |
|
362 |
firstMatch = j; |
|
363 |
matches++; |
|
364 |
} else { |
|
365 |
if (indexes == null) { |
|
366 |
indexes = new int[items.length]; |
|
367 |
indexes[0] = firstMatch; |
|
368 |
} |
|
369 |
indexes[matches++] = j; |
|
370 |
} |
|
371 |
} |
|
3974
711cc3e0bd63
6827786: Mnemonic cycling for multiple equal mnemonic armed menu items stops when encountering a submenu
peterz
parents:
1639
diff
changeset
|
372 |
if (item.isArmed() || item.isSelected()) { |
2 | 373 |
currentIndex = matches - 1; |
374 |
} |
|
375 |
} |
|
376 |
||
377 |
if (matches == 0) { |
|
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
378 |
// no op |
2 | 379 |
} else if (matches == 1) { |
380 |
// Invoke the menu action |
|
381 |
JMenuItem item = (JMenuItem)items[firstMatch]; |
|
382 |
if (item instanceof JMenu) { |
|
383 |
// submenus are handled in menuKeyTyped |
|
384 |
menuToOpen = item; |
|
385 |
} else if (item.isEnabled()) { |
|
386 |
// we have a menu item |
|
387 |
manager.clearSelectedPath(); |
|
388 |
item.doClick(); |
|
389 |
} |
|
390 |
e.consume(); |
|
391 |
} else { |
|
392 |
// Select the menu item with the matching mnemonic. If |
|
393 |
// the same mnemonic has been invoked then select the next |
|
394 |
// menu item in the cycle. |
|
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
395 |
MenuElement newItem; |
2 | 396 |
|
397 |
newItem = items[indexes[(currentIndex + 1) % matches]]; |
|
398 |
||
399 |
MenuElement newPath[] = new MenuElement[path.length+1]; |
|
400 |
System.arraycopy(path, 0, newPath, 0, path.length); |
|
401 |
newPath[path.length] = newItem; |
|
402 |
manager.setSelectedPath(newPath); |
|
403 |
e.consume(); |
|
404 |
} |
|
405 |
} |
|
406 |
||
407 |
public void menuKeyReleased(MenuKeyEvent e) { |
|
408 |
} |
|
409 |
||
410 |
private char lower(char keyChar) { |
|
411 |
return Character.toLowerCase(keyChar); |
|
412 |
} |
|
413 |
||
414 |
private char lower(int mnemonic) { |
|
415 |
return Character.toLowerCase((char) mnemonic); |
|
416 |
} |
|
417 |
} |
|
418 |
||
419 |
private static class Actions extends UIAction { |
|
420 |
// Types of actions |
|
421 |
private static final String CANCEL = "cancel"; |
|
422 |
private static final String SELECT_NEXT = "selectNext"; |
|
423 |
private static final String SELECT_PREVIOUS = "selectPrevious"; |
|
424 |
private static final String SELECT_PARENT = "selectParent"; |
|
425 |
private static final String SELECT_CHILD = "selectChild"; |
|
426 |
private static final String RETURN = "return"; |
|
427 |
||
428 |
// Used for next/previous actions |
|
429 |
private static final boolean FORWARD = true; |
|
430 |
private static final boolean BACKWARD = false; |
|
431 |
||
432 |
// Used for parent/child actions |
|
433 |
private static final boolean PARENT = false; |
|
434 |
private static final boolean CHILD = true; |
|
435 |
||
436 |
||
437 |
Actions(String key) { |
|
438 |
super(key); |
|
439 |
} |
|
440 |
||
441 |
public void actionPerformed(ActionEvent e) { |
|
442 |
String key = getName(); |
|
443 |
if (key == CANCEL) { |
|
444 |
cancel(); |
|
445 |
} |
|
446 |
else if (key == SELECT_NEXT) { |
|
447 |
selectItem(FORWARD); |
|
448 |
} |
|
449 |
else if (key == SELECT_PREVIOUS) { |
|
450 |
selectItem(BACKWARD); |
|
451 |
} |
|
452 |
else if (key == SELECT_PARENT) { |
|
453 |
selectParentChild(PARENT); |
|
454 |
} |
|
455 |
else if (key == SELECT_CHILD) { |
|
456 |
selectParentChild(CHILD); |
|
457 |
} |
|
458 |
else if (key == RETURN) { |
|
459 |
doReturn(); |
|
460 |
} |
|
461 |
} |
|
462 |
||
463 |
private void doReturn() { |
|
464 |
KeyboardFocusManager fmgr = |
|
465 |
KeyboardFocusManager.getCurrentKeyboardFocusManager(); |
|
466 |
Component focusOwner = fmgr.getFocusOwner(); |
|
467 |
if(focusOwner != null && !(focusOwner instanceof JRootPane)) { |
|
468 |
return; |
|
469 |
} |
|
470 |
||
471 |
MenuSelectionManager msm = MenuSelectionManager.defaultManager(); |
|
472 |
MenuElement path[] = msm.getSelectedPath(); |
|
473 |
MenuElement lastElement; |
|
474 |
if(path.length > 0) { |
|
475 |
lastElement = path[path.length-1]; |
|
476 |
if(lastElement instanceof JMenu) { |
|
477 |
MenuElement newPath[] = new MenuElement[path.length+1]; |
|
478 |
System.arraycopy(path,0,newPath,0,path.length); |
|
479 |
newPath[path.length] = ((JMenu)lastElement).getPopupMenu(); |
|
480 |
msm.setSelectedPath(newPath); |
|
481 |
} else if(lastElement instanceof JMenuItem) { |
|
482 |
JMenuItem mi = (JMenuItem)lastElement; |
|
483 |
||
484 |
if (mi.getUI() instanceof BasicMenuItemUI) { |
|
485 |
((BasicMenuItemUI)mi.getUI()).doClick(msm); |
|
486 |
} |
|
487 |
else { |
|
488 |
msm.clearSelectedPath(); |
|
489 |
mi.doClick(0); |
|
490 |
} |
|
491 |
} |
|
492 |
} |
|
493 |
} |
|
494 |
private void selectParentChild(boolean direction) { |
|
495 |
MenuSelectionManager msm = MenuSelectionManager.defaultManager(); |
|
496 |
MenuElement path[] = msm.getSelectedPath(); |
|
497 |
int len = path.length; |
|
498 |
||
499 |
if (direction == PARENT) { |
|
500 |
// selecting parent |
|
501 |
int popupIndex = len-1; |
|
502 |
||
503 |
if (len > 2 && |
|
504 |
// check if we have an open submenu. A submenu item may or |
|
505 |
// may not be selected, so submenu popup can be either the |
|
506 |
// last or next to the last item. |
|
507 |
(path[popupIndex] instanceof JPopupMenu || |
|
508 |
path[--popupIndex] instanceof JPopupMenu) && |
|
509 |
!((JMenu)path[popupIndex-1]).isTopLevelMenu()) { |
|
510 |
||
511 |
// we have a submenu, just close it |
|
512 |
MenuElement newPath[] = new MenuElement[popupIndex]; |
|
513 |
System.arraycopy(path, 0, newPath, 0, popupIndex); |
|
514 |
msm.setSelectedPath(newPath); |
|
515 |
return; |
|
516 |
} |
|
517 |
} else { |
|
518 |
// selecting child |
|
519 |
if (len > 0 && path[len-1] instanceof JMenu && |
|
520 |
!((JMenu)path[len-1]).isTopLevelMenu()) { |
|
521 |
||
522 |
// we have a submenu, open it |
|
523 |
JMenu menu = (JMenu)path[len-1]; |
|
524 |
JPopupMenu popup = menu.getPopupMenu(); |
|
525 |
MenuElement[] subs = popup.getSubElements(); |
|
526 |
MenuElement item = findEnabledChild(subs, -1, true); |
|
527 |
MenuElement[] newPath; |
|
528 |
||
529 |
if (item == null) { |
|
530 |
newPath = new MenuElement[len+1]; |
|
531 |
} else { |
|
532 |
newPath = new MenuElement[len+2]; |
|
533 |
newPath[len+1] = item; |
|
534 |
} |
|
535 |
System.arraycopy(path, 0, newPath, 0, len); |
|
536 |
newPath[len] = popup; |
|
537 |
msm.setSelectedPath(newPath); |
|
538 |
return; |
|
539 |
} |
|
540 |
} |
|
541 |
||
542 |
// check if we have a toplevel menu selected. |
|
543 |
// If this is the case, we select another toplevel menu |
|
544 |
if (len > 1 && path[0] instanceof JMenuBar) { |
|
545 |
MenuElement currentMenu = path[1]; |
|
546 |
MenuElement nextMenu = findEnabledChild( |
|
547 |
path[0].getSubElements(), currentMenu, direction); |
|
548 |
||
549 |
if (nextMenu != null && nextMenu != currentMenu) { |
|
550 |
MenuElement newSelection[]; |
|
551 |
if (len == 2) { |
|
552 |
// menu is selected but its popup not shown |
|
553 |
newSelection = new MenuElement[2]; |
|
554 |
newSelection[0] = path[0]; |
|
555 |
newSelection[1] = nextMenu; |
|
556 |
} else { |
|
557 |
// menu is selected and its popup is shown |
|
558 |
newSelection = new MenuElement[3]; |
|
559 |
newSelection[0] = path[0]; |
|
560 |
newSelection[1] = nextMenu; |
|
561 |
newSelection[2] = ((JMenu)nextMenu).getPopupMenu(); |
|
562 |
} |
|
563 |
msm.setSelectedPath(newSelection); |
|
564 |
} |
|
565 |
} |
|
566 |
} |
|
567 |
||
568 |
private void selectItem(boolean direction) { |
|
569 |
MenuSelectionManager msm = MenuSelectionManager.defaultManager(); |
|
570 |
MenuElement path[] = msm.getSelectedPath(); |
|
571 |
if (path.length == 0) { |
|
572 |
return; |
|
573 |
} |
|
574 |
int len = path.length; |
|
575 |
if (len == 1 && path[0] instanceof JPopupMenu) { |
|
576 |
||
577 |
JPopupMenu popup = (JPopupMenu) path[0]; |
|
578 |
MenuElement[] newPath = new MenuElement[2]; |
|
579 |
newPath[0] = popup; |
|
580 |
newPath[1] = findEnabledChild(popup.getSubElements(), -1, direction); |
|
581 |
msm.setSelectedPath(newPath); |
|
582 |
} else if (len == 2 && |
|
583 |
path[0] instanceof JMenuBar && path[1] instanceof JMenu) { |
|
584 |
||
585 |
// a toplevel menu is selected, but its popup not shown. |
|
586 |
// Show the popup and select the first item |
|
587 |
JPopupMenu popup = ((JMenu)path[1]).getPopupMenu(); |
|
588 |
MenuElement next = |
|
589 |
findEnabledChild(popup.getSubElements(), -1, FORWARD); |
|
590 |
MenuElement[] newPath; |
|
591 |
||
592 |
if (next != null) { |
|
593 |
// an enabled item found -- include it in newPath |
|
594 |
newPath = new MenuElement[4]; |
|
595 |
newPath[3] = next; |
|
596 |
} else { |
|
597 |
// menu has no enabled items -- still must show the popup |
|
598 |
newPath = new MenuElement[3]; |
|
599 |
} |
|
600 |
System.arraycopy(path, 0, newPath, 0, 2); |
|
601 |
newPath[2] = popup; |
|
602 |
msm.setSelectedPath(newPath); |
|
603 |
||
604 |
} else if (path[len-1] instanceof JPopupMenu && |
|
605 |
path[len-2] instanceof JMenu) { |
|
606 |
||
607 |
// a menu (not necessarily toplevel) is open and its popup |
|
608 |
// shown. Select the appropriate menu item |
|
609 |
JMenu menu = (JMenu)path[len-2]; |
|
610 |
JPopupMenu popup = menu.getPopupMenu(); |
|
611 |
MenuElement next = |
|
612 |
findEnabledChild(popup.getSubElements(), -1, direction); |
|
613 |
||
614 |
if (next != null) { |
|
615 |
MenuElement[] newPath = new MenuElement[len+1]; |
|
616 |
System.arraycopy(path, 0, newPath, 0, len); |
|
617 |
newPath[len] = next; |
|
618 |
msm.setSelectedPath(newPath); |
|
619 |
} else { |
|
620 |
// all items in the popup are disabled. |
|
621 |
// We're going to find the parent popup menu and select |
|
622 |
// its next item. If there's no parent popup menu (i.e. |
|
623 |
// current menu is toplevel), do nothing |
|
624 |
if (len > 2 && path[len-3] instanceof JPopupMenu) { |
|
625 |
popup = ((JPopupMenu)path[len-3]); |
|
626 |
next = findEnabledChild(popup.getSubElements(), |
|
627 |
menu, direction); |
|
628 |
||
629 |
if (next != null && next != menu) { |
|
630 |
MenuElement[] newPath = new MenuElement[len-1]; |
|
631 |
System.arraycopy(path, 0, newPath, 0, len-2); |
|
632 |
newPath[len-2] = next; |
|
633 |
msm.setSelectedPath(newPath); |
|
634 |
} |
|
635 |
} |
|
636 |
} |
|
637 |
||
638 |
} else { |
|
639 |
// just select the next item, no path expansion needed |
|
640 |
MenuElement subs[] = path[len-2].getSubElements(); |
|
641 |
MenuElement nextChild = |
|
642 |
findEnabledChild(subs, path[len-1], direction); |
|
643 |
if (nextChild == null) { |
|
644 |
nextChild = findEnabledChild(subs, -1, direction); |
|
645 |
} |
|
646 |
if (nextChild != null) { |
|
647 |
path[len-1] = nextChild; |
|
648 |
msm.setSelectedPath(path); |
|
649 |
} |
|
650 |
} |
|
651 |
} |
|
652 |
||
653 |
private void cancel() { |
|
654 |
// 4234793: This action should call JPopupMenu.firePopupMenuCanceled but it's |
|
655 |
// a protected method. The real solution could be to make |
|
656 |
// firePopupMenuCanceled public and call it directly. |
|
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
657 |
JPopupMenu lastPopup = getLastPopup(); |
2 | 658 |
if (lastPopup != null) { |
659 |
lastPopup.putClientProperty("JPopupMenu.firePopupMenuCanceled", Boolean.TRUE); |
|
660 |
} |
|
661 |
String mode = UIManager.getString("Menu.cancelMode"); |
|
662 |
if ("hideMenuTree".equals(mode)) { |
|
663 |
MenuSelectionManager.defaultManager().clearSelectedPath(); |
|
664 |
} else { |
|
665 |
shortenSelectedPath(); |
|
666 |
} |
|
667 |
} |
|
668 |
||
669 |
private void shortenSelectedPath() { |
|
670 |
MenuElement path[] = MenuSelectionManager.defaultManager().getSelectedPath(); |
|
671 |
if (path.length <= 2) { |
|
672 |
MenuSelectionManager.defaultManager().clearSelectedPath(); |
|
673 |
return; |
|
674 |
} |
|
675 |
// unselect MenuItem and its Popup by default |
|
676 |
int value = 2; |
|
677 |
MenuElement lastElement = path[path.length - 1]; |
|
678 |
JPopupMenu lastPopup = getLastPopup(); |
|
679 |
if (lastElement == lastPopup) { |
|
680 |
MenuElement previousElement = path[path.length - 2]; |
|
681 |
if (previousElement instanceof JMenu) { |
|
682 |
JMenu lastMenu = (JMenu) previousElement; |
|
683 |
if (lastMenu.isEnabled() && lastPopup.getComponentCount() > 0) { |
|
684 |
// unselect the last visible popup only |
|
685 |
value = 1; |
|
686 |
} else { |
|
687 |
// unselect invisible popup and two visible elements |
|
688 |
value = 3; |
|
689 |
} |
|
690 |
} |
|
691 |
} |
|
692 |
if (path.length - value <= 2 |
|
693 |
&& !UIManager.getBoolean("Menu.preserveTopLevelSelection")) { |
|
694 |
// clear selection for the topLevelMenu |
|
695 |
value = path.length; |
|
696 |
} |
|
697 |
MenuElement newPath[] = new MenuElement[path.length - value]; |
|
698 |
System.arraycopy(path, 0, newPath, 0, path.length - value); |
|
699 |
MenuSelectionManager.defaultManager().setSelectedPath(newPath); |
|
700 |
} |
|
701 |
} |
|
702 |
||
703 |
private static MenuElement nextEnabledChild(MenuElement e[], |
|
704 |
int fromIndex, int toIndex) { |
|
705 |
for (int i=fromIndex; i<=toIndex; i++) { |
|
706 |
if (e[i] != null) { |
|
707 |
Component comp = e[i].getComponent(); |
|
708 |
if ( comp != null |
|
709 |
&& (comp.isEnabled() || UIManager.getBoolean("MenuItem.disabledAreNavigable")) |
|
710 |
&& comp.isVisible()) { |
|
711 |
return e[i]; |
|
712 |
} |
|
713 |
} |
|
714 |
} |
|
715 |
return null; |
|
716 |
} |
|
717 |
||
718 |
private static MenuElement previousEnabledChild(MenuElement e[], |
|
719 |
int fromIndex, int toIndex) { |
|
720 |
for (int i=fromIndex; i>=toIndex; i--) { |
|
721 |
if (e[i] != null) { |
|
722 |
Component comp = e[i].getComponent(); |
|
723 |
if ( comp != null |
|
724 |
&& (comp.isEnabled() || UIManager.getBoolean("MenuItem.disabledAreNavigable")) |
|
725 |
&& comp.isVisible()) { |
|
726 |
return e[i]; |
|
727 |
} |
|
728 |
} |
|
729 |
} |
|
730 |
return null; |
|
731 |
} |
|
732 |
||
733 |
static MenuElement findEnabledChild(MenuElement e[], int fromIndex, |
|
734 |
boolean forward) { |
|
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
735 |
MenuElement result; |
2 | 736 |
if (forward) { |
737 |
result = nextEnabledChild(e, fromIndex+1, e.length-1); |
|
738 |
if (result == null) result = nextEnabledChild(e, 0, fromIndex-1); |
|
739 |
} else { |
|
740 |
result = previousEnabledChild(e, fromIndex-1, 0); |
|
741 |
if (result == null) result = previousEnabledChild(e, e.length-1, |
|
742 |
fromIndex+1); |
|
743 |
} |
|
744 |
return result; |
|
745 |
} |
|
746 |
||
747 |
static MenuElement findEnabledChild(MenuElement e[], |
|
748 |
MenuElement elem, boolean forward) { |
|
749 |
for (int i=0; i<e.length; i++) { |
|
750 |
if (e[i] == elem) { |
|
751 |
return findEnabledChild(e, i, forward); |
|
752 |
} |
|
753 |
} |
|
754 |
return null; |
|
755 |
} |
|
756 |
||
757 |
static class MouseGrabber implements ChangeListener, |
|
758 |
AWTEventListener, ComponentListener, WindowListener { |
|
759 |
||
760 |
Window grabbedWindow; |
|
761 |
MenuElement[] lastPathSelected; |
|
762 |
||
763 |
public MouseGrabber() { |
|
764 |
MenuSelectionManager msm = MenuSelectionManager.defaultManager(); |
|
765 |
msm.addChangeListener(this); |
|
766 |
this.lastPathSelected = msm.getSelectedPath(); |
|
767 |
if(this.lastPathSelected.length != 0) { |
|
768 |
grabWindow(this.lastPathSelected); |
|
769 |
} |
|
770 |
} |
|
771 |
||
772 |
void uninstall() { |
|
773 |
synchronized (MOUSE_GRABBER_KEY) { |
|
774 |
MenuSelectionManager.defaultManager().removeChangeListener(this); |
|
775 |
ungrabWindow(); |
|
776 |
AppContext.getAppContext().remove(MOUSE_GRABBER_KEY); |
|
777 |
} |
|
778 |
} |
|
779 |
||
780 |
void grabWindow(MenuElement[] newPath) { |
|
781 |
// A grab needs to be added |
|
782 |
final Toolkit tk = Toolkit.getDefaultToolkit(); |
|
783 |
java.security.AccessController.doPrivileged( |
|
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
784 |
new java.security.PrivilegedAction<Object>() { |
2 | 785 |
public Object run() { |
786 |
tk.addAWTEventListener(MouseGrabber.this, |
|
787 |
AWTEvent.MOUSE_EVENT_MASK | |
|
788 |
AWTEvent.MOUSE_MOTION_EVENT_MASK | |
|
789 |
AWTEvent.MOUSE_WHEEL_EVENT_MASK | |
|
790 |
AWTEvent.WINDOW_EVENT_MASK | sun.awt.SunToolkit.GRAB_EVENT_MASK); |
|
791 |
return null; |
|
792 |
} |
|
793 |
} |
|
794 |
); |
|
795 |
||
796 |
Component invoker = newPath[0].getComponent(); |
|
797 |
if (invoker instanceof JPopupMenu) { |
|
798 |
invoker = ((JPopupMenu)invoker).getInvoker(); |
|
799 |
} |
|
800 |
grabbedWindow = invoker instanceof Window? |
|
801 |
(Window)invoker : |
|
802 |
SwingUtilities.getWindowAncestor(invoker); |
|
803 |
if(grabbedWindow != null) { |
|
804 |
if(tk instanceof sun.awt.SunToolkit) { |
|
805 |
((sun.awt.SunToolkit)tk).grab(grabbedWindow); |
|
806 |
} else { |
|
807 |
grabbedWindow.addComponentListener(this); |
|
808 |
grabbedWindow.addWindowListener(this); |
|
809 |
} |
|
810 |
} |
|
811 |
} |
|
812 |
||
813 |
void ungrabWindow() { |
|
814 |
final Toolkit tk = Toolkit.getDefaultToolkit(); |
|
815 |
// The grab should be removed |
|
816 |
java.security.AccessController.doPrivileged( |
|
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
817 |
new java.security.PrivilegedAction<Object>() { |
2 | 818 |
public Object run() { |
819 |
tk.removeAWTEventListener(MouseGrabber.this); |
|
820 |
return null; |
|
821 |
} |
|
822 |
} |
|
823 |
); |
|
824 |
realUngrabWindow(); |
|
825 |
} |
|
826 |
||
827 |
void realUngrabWindow() { |
|
828 |
Toolkit tk = Toolkit.getDefaultToolkit(); |
|
829 |
if(grabbedWindow != null) { |
|
830 |
if(tk instanceof sun.awt.SunToolkit) { |
|
831 |
((sun.awt.SunToolkit)tk).ungrab(grabbedWindow); |
|
832 |
} else { |
|
833 |
grabbedWindow.removeComponentListener(this); |
|
834 |
grabbedWindow.removeWindowListener(this); |
|
835 |
} |
|
836 |
grabbedWindow = null; |
|
837 |
} |
|
838 |
} |
|
839 |
||
840 |
public void stateChanged(ChangeEvent e) { |
|
841 |
MenuSelectionManager msm = MenuSelectionManager.defaultManager(); |
|
842 |
MenuElement[] p = msm.getSelectedPath(); |
|
843 |
||
844 |
if (lastPathSelected.length == 0 && p.length != 0) { |
|
845 |
grabWindow(p); |
|
846 |
} |
|
847 |
||
848 |
if (lastPathSelected.length != 0 && p.length == 0) { |
|
849 |
ungrabWindow(); |
|
850 |
} |
|
851 |
||
852 |
lastPathSelected = p; |
|
853 |
} |
|
854 |
||
855 |
public void eventDispatched(AWTEvent ev) { |
|
856 |
if(ev instanceof sun.awt.UngrabEvent) { |
|
857 |
// Popup should be canceled in case of ungrab event |
|
858 |
cancelPopupMenu( ); |
|
859 |
return; |
|
860 |
} |
|
861 |
if (!(ev instanceof MouseEvent)) { |
|
862 |
// We are interested in MouseEvents only |
|
863 |
return; |
|
864 |
} |
|
865 |
MouseEvent me = (MouseEvent) ev; |
|
866 |
Component src = me.getComponent(); |
|
867 |
switch (me.getID()) { |
|
868 |
case MouseEvent.MOUSE_PRESSED: |
|
869 |
if (isInPopup(src) || |
|
870 |
(src instanceof JMenu && ((JMenu)src).isSelected())) { |
|
871 |
return; |
|
872 |
} |
|
873 |
if (!(src instanceof JComponent) || |
|
874 |
! (((JComponent)src).getClientProperty("doNotCancelPopup") |
|
875 |
== BasicComboBoxUI.HIDE_POPUP_KEY)) { |
|
876 |
// Cancel popup only if this property was not set. |
|
877 |
// If this property is set to TRUE component wants |
|
878 |
// to deal with this event by himself. |
|
879 |
cancelPopupMenu(); |
|
880 |
// Ask UIManager about should we consume event that closes |
|
881 |
// popup. This made to match native apps behaviour. |
|
882 |
boolean consumeEvent = |
|
883 |
UIManager.getBoolean("PopupMenu.consumeEventOnClose"); |
|
884 |
// Consume the event so that normal processing stops. |
|
885 |
if(consumeEvent && !(src instanceof MenuElement)) { |
|
886 |
me.consume(); |
|
887 |
} |
|
888 |
} |
|
889 |
break; |
|
890 |
||
891 |
case MouseEvent.MOUSE_RELEASED: |
|
892 |
if(!(src instanceof MenuElement)) { |
|
893 |
// Do not forward event to MSM, let component handle it |
|
894 |
if (isInPopup(src)) { |
|
895 |
break; |
|
896 |
} |
|
897 |
} |
|
898 |
if(src instanceof JMenu || !(src instanceof JMenuItem)) { |
|
899 |
MenuSelectionManager.defaultManager(). |
|
900 |
processMouseEvent(me); |
|
901 |
} |
|
902 |
break; |
|
903 |
case MouseEvent.MOUSE_DRAGGED: |
|
904 |
if(!(src instanceof MenuElement)) { |
|
905 |
// For the MOUSE_DRAGGED event the src is |
|
906 |
// the Component in which mouse button was pressed. |
|
907 |
// If the src is in popupMenu, |
|
908 |
// do not forward event to MSM, let component handle it. |
|
909 |
if (isInPopup(src)) { |
|
910 |
break; |
|
911 |
} |
|
912 |
} |
|
913 |
MenuSelectionManager.defaultManager(). |
|
914 |
processMouseEvent(me); |
|
915 |
break; |
|
916 |
case MouseEvent.MOUSE_WHEEL: |
|
917 |
if (isInPopup(src)) { |
|
918 |
return; |
|
919 |
} |
|
920 |
cancelPopupMenu(); |
|
921 |
break; |
|
922 |
} |
|
923 |
} |
|
924 |
||
925 |
boolean isInPopup(Component src) { |
|
926 |
for (Component c=src; c!=null; c=c.getParent()) { |
|
927 |
if (c instanceof Applet || c instanceof Window) { |
|
928 |
break; |
|
929 |
} else if (c instanceof JPopupMenu) { |
|
930 |
return true; |
|
931 |
} |
|
932 |
} |
|
933 |
return false; |
|
934 |
} |
|
935 |
||
936 |
void cancelPopupMenu() { |
|
937 |
// We should ungrab window if a user code throws |
|
938 |
// an unexpected runtime exception. See 6495920. |
|
939 |
try { |
|
940 |
// 4234793: This action should call firePopupMenuCanceled but it's |
|
941 |
// a protected method. The real solution could be to make |
|
942 |
// firePopupMenuCanceled public and call it directly. |
|
1290
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
943 |
List<JPopupMenu> popups = getPopups(); |
da8902cd496c
6727661: Code improvement and warnings removing from the swing/plaf packages
rupashka
parents:
2
diff
changeset
|
944 |
for (JPopupMenu popup : popups) { |
2 | 945 |
popup.putClientProperty("JPopupMenu.firePopupMenuCanceled", Boolean.TRUE); |
946 |
} |
|
947 |
MenuSelectionManager.defaultManager().clearSelectedPath(); |
|
948 |
} catch (RuntimeException ex) { |
|
949 |
realUngrabWindow(); |
|
950 |
throw ex; |
|
951 |
} catch (Error err) { |
|
952 |
realUngrabWindow(); |
|
953 |
throw err; |
|
954 |
} |
|
955 |
} |
|
956 |
||
957 |
public void componentResized(ComponentEvent e) { |
|
958 |
cancelPopupMenu(); |
|
959 |
} |
|
960 |
public void componentMoved(ComponentEvent e) { |
|
961 |
cancelPopupMenu(); |
|
962 |
} |
|
963 |
public void componentShown(ComponentEvent e) { |
|
964 |
cancelPopupMenu(); |
|
965 |
} |
|
966 |
public void componentHidden(ComponentEvent e) { |
|
967 |
cancelPopupMenu(); |
|
968 |
} |
|
969 |
public void windowClosing(WindowEvent e) { |
|
970 |
cancelPopupMenu(); |
|
971 |
} |
|
972 |
public void windowClosed(WindowEvent e) { |
|
973 |
cancelPopupMenu(); |
|
974 |
} |
|
975 |
public void windowIconified(WindowEvent e) { |
|
976 |
cancelPopupMenu(); |
|
977 |
} |
|
978 |
public void windowDeactivated(WindowEvent e) { |
|
979 |
cancelPopupMenu(); |
|
980 |
} |
|
981 |
public void windowOpened(WindowEvent e) {} |
|
982 |
public void windowDeiconified(WindowEvent e) {} |
|
983 |
public void windowActivated(WindowEvent e) {} |
|
984 |
} |
|
985 |
||
986 |
/** |
|
987 |
* This helper is added to MenuSelectionManager as a ChangeListener to |
|
988 |
* listen to menu selection changes. When a menu is activated, it passes |
|
989 |
* focus to its parent JRootPane, and installs an ActionMap/InputMap pair |
|
990 |
* on that JRootPane. Those maps are necessary in order for menu |
|
991 |
* navigation to work. When menu is being deactivated, it restores focus |
|
992 |
* to the component that has had it before menu activation, and uninstalls |
|
993 |
* the maps. |
|
994 |
* This helper is also installed as a KeyListener on root pane when menu |
|
995 |
* is active. It forwards key events to MenuSelectionManager for mnemonic |
|
996 |
* keys handling. |
|
997 |
*/ |
|
998 |
static class MenuKeyboardHelper |
|
999 |
implements ChangeListener, KeyListener { |
|
1000 |
||
1001 |
private Component lastFocused = null; |
|
1002 |
private MenuElement[] lastPathSelected = new MenuElement[0]; |
|
1003 |
private JPopupMenu lastPopup; |
|
1004 |
||
1005 |
private JRootPane invokerRootPane; |
|
1006 |
private ActionMap menuActionMap = getActionMap(); |
|
1007 |
private InputMap menuInputMap; |
|
1008 |
private boolean focusTraversalKeysEnabled; |
|
1009 |
||
1010 |
/* |
|
1011 |
* Fix for 4213634 |
|
1012 |
* If this is false, KEY_TYPED and KEY_RELEASED events are NOT |
|
1013 |
* processed. This is needed to avoid activating a menuitem when |
|
1014 |
* the menu and menuitem share the same mnemonic. |
|
1015 |
*/ |
|
1016 |
private boolean receivedKeyPressed = false; |
|
1017 |
||
1018 |
void removeItems() { |
|
1019 |
if (lastFocused != null) { |
|
1020 |
if(!lastFocused.requestFocusInWindow()) { |
|
1021 |
// Workarounr for 4810575. |
|
1022 |
// If lastFocused is not in currently focused window |
|
1023 |
// requestFocusInWindow will fail. In this case we must |
|
1024 |
// request focus by requestFocus() if it was not |
|
1025 |
// transferred from our popup. |
|
1026 |
Window cfw = KeyboardFocusManager |
|
1027 |
.getCurrentKeyboardFocusManager() |
|
1028 |
.getFocusedWindow(); |
|
1029 |
if(cfw != null && |
|
1030 |
"###focusableSwingPopup###".equals(cfw.getName())) { |
|
1031 |
lastFocused.requestFocus(); |
|
1032 |
} |
|
1033 |
||
1034 |
} |
|
1035 |
lastFocused = null; |
|
1036 |
} |
|
1037 |
if (invokerRootPane != null) { |
|
1038 |
invokerRootPane.removeKeyListener(this); |
|
1039 |
invokerRootPane.setFocusTraversalKeysEnabled(focusTraversalKeysEnabled); |
|
1040 |
removeUIInputMap(invokerRootPane, menuInputMap); |
|
1041 |
removeUIActionMap(invokerRootPane, menuActionMap); |
|
1042 |
invokerRootPane = null; |
|
1043 |
} |
|
1044 |
receivedKeyPressed = false; |
|
1045 |
} |
|
1046 |
||
1047 |
private FocusListener rootPaneFocusListener = new FocusAdapter() { |
|
1048 |
public void focusGained(FocusEvent ev) { |
|
1049 |
Component opposite = ev.getOppositeComponent(); |
|
1050 |
if (opposite != null) { |
|
1051 |
lastFocused = opposite; |
|
1052 |
} |
|
1053 |
ev.getComponent().removeFocusListener(this); |
|
1054 |
} |
|
1055 |
}; |
|
1056 |
||
1057 |
/** |
|
1058 |
* Return the last JPopupMenu in <code>path</code>, |
|
1059 |
* or <code>null</code> if none found |
|
1060 |
*/ |
|
1061 |
JPopupMenu getActivePopup(MenuElement[] path) { |
|
1062 |
for (int i=path.length-1; i>=0; i--) { |
|
1063 |
MenuElement elem = path[i]; |
|
1064 |
if (elem instanceof JPopupMenu) { |
|
1065 |
return (JPopupMenu)elem; |
|
1066 |
} |
|
1067 |
} |
|
1068 |
return null; |
|
1069 |
} |
|
1070 |
||
1071 |
void addUIInputMap(JComponent c, InputMap map) { |
|
1072 |
InputMap lastNonUI = null; |
|
1073 |
InputMap parent = c.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); |
|
1074 |
||
1075 |
while (parent != null && !(parent instanceof UIResource)) { |
|
1076 |
lastNonUI = parent; |
|
1077 |
parent = parent.getParent(); |
|
1078 |
} |
|
1079 |
||
1080 |
if (lastNonUI == null) { |
|
1081 |
c.setInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, map); |
|
1082 |
} else { |
|
1083 |
lastNonUI.setParent(map); |
|
1084 |
} |
|
1085 |
map.setParent(parent); |
|
1086 |
} |
|
1087 |
||
1088 |
void addUIActionMap(JComponent c, ActionMap map) { |
|
1089 |
ActionMap lastNonUI = null; |
|
1090 |
ActionMap parent = c.getActionMap(); |
|
1091 |
||
1092 |
while (parent != null && !(parent instanceof UIResource)) { |
|
1093 |
lastNonUI = parent; |
|
1094 |
parent = parent.getParent(); |
|
1095 |
} |
|
1096 |
||
1097 |
if (lastNonUI == null) { |
|
1098 |
c.setActionMap(map); |
|
1099 |
} else { |
|
1100 |
lastNonUI.setParent(map); |
|
1101 |
} |
|
1102 |
map.setParent(parent); |
|
1103 |
} |
|
1104 |
||
1105 |
void removeUIInputMap(JComponent c, InputMap map) { |
|
1106 |
InputMap im = null; |
|
1107 |
InputMap parent = c.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); |
|
1108 |
||
1109 |
while (parent != null) { |
|
1110 |
if (parent == map) { |
|
1111 |
if (im == null) { |
|
1112 |
c.setInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, |
|
1113 |
map.getParent()); |
|
1114 |
} else { |
|
1115 |
im.setParent(map.getParent()); |
|
1116 |
} |
|
1117 |
break; |
|
1118 |
} |
|
1119 |
im = parent; |
|
1120 |
parent = parent.getParent(); |
|
1121 |
} |
|
1122 |
} |
|
1123 |
||
1124 |
void removeUIActionMap(JComponent c, ActionMap map) { |
|
1125 |
ActionMap im = null; |
|
1126 |
ActionMap parent = c.getActionMap(); |
|
1127 |
||
1128 |
while (parent != null) { |
|
1129 |
if (parent == map) { |
|
1130 |
if (im == null) { |
|
1131 |
c.setActionMap(map.getParent()); |
|
1132 |
} else { |
|
1133 |
im.setParent(map.getParent()); |
|
1134 |
} |
|
1135 |
break; |
|
1136 |
} |
|
1137 |
im = parent; |
|
1138 |
parent = parent.getParent(); |
|
1139 |
} |
|
1140 |
} |
|
1141 |
||
1142 |
public void stateChanged(ChangeEvent ev) { |
|
1143 |
if (!(UIManager.getLookAndFeel() instanceof BasicLookAndFeel)) { |
|
1144 |
uninstall(); |
|
1145 |
return; |
|
1146 |
} |
|
1147 |
MenuSelectionManager msm = (MenuSelectionManager)ev.getSource(); |
|
1148 |
MenuElement[] p = msm.getSelectedPath(); |
|
1149 |
JPopupMenu popup = getActivePopup(p); |
|
1150 |
if (popup != null && !popup.isFocusable()) { |
|
1151 |
// Do nothing for non-focusable popups |
|
1152 |
return; |
|
1153 |
} |
|
1154 |
||
1155 |
if (lastPathSelected.length != 0 && p.length != 0 ) { |
|
1156 |
if (!checkInvokerEqual(p[0],lastPathSelected[0])) { |
|
1157 |
removeItems(); |
|
1158 |
lastPathSelected = new MenuElement[0]; |
|
1159 |
} |
|
1160 |
} |
|
1161 |
||
1162 |
if (lastPathSelected.length == 0 && p.length > 0) { |
|
1163 |
// menu posted |
|
1164 |
JComponent invoker; |
|
1165 |
||
1166 |
if (popup == null) { |
|
1167 |
if (p.length == 2 && p[0] instanceof JMenuBar && |
|
1168 |
p[1] instanceof JMenu) { |
|
1169 |
// a menu has been selected but not open |
|
1170 |
invoker = (JComponent)p[1]; |
|
1171 |
popup = ((JMenu)invoker).getPopupMenu(); |
|
1172 |
} else { |
|
1173 |
return; |
|
1174 |
} |
|
1175 |
} else { |
|
1176 |
Component c = popup.getInvoker(); |
|
1177 |
if(c instanceof JFrame) { |
|
1178 |
invoker = ((JFrame)c).getRootPane(); |
|
1179 |
} else if(c instanceof JDialog) { |
|
1180 |
invoker = ((JDialog)c).getRootPane(); |
|
1181 |
} else if(c instanceof JApplet) { |
|
1182 |
invoker = ((JApplet)c).getRootPane(); |
|
1183 |
} else { |
|
1184 |
while (!(c instanceof JComponent)) { |
|
1185 |
if (c == null) { |
|
1186 |
return; |
|
1187 |
} |
|
1188 |
c = c.getParent(); |
|
1189 |
} |
|
1190 |
invoker = (JComponent)c; |
|
1191 |
} |
|
1192 |
} |
|
1193 |
||
1194 |
// remember current focus owner |
|
1195 |
lastFocused = KeyboardFocusManager. |
|
1196 |
getCurrentKeyboardFocusManager().getFocusOwner(); |
|
1197 |
||
1198 |
// request focus on root pane and install keybindings |
|
1199 |
// used for menu navigation |
|
1200 |
invokerRootPane = SwingUtilities.getRootPane(invoker); |
|
1201 |
if (invokerRootPane != null) { |
|
1202 |
invokerRootPane.addFocusListener(rootPaneFocusListener); |
|
1203 |
invokerRootPane.requestFocus(true); |
|
1204 |
invokerRootPane.addKeyListener(this); |
|
1205 |
focusTraversalKeysEnabled = invokerRootPane. |
|
1206 |
getFocusTraversalKeysEnabled(); |
|
1207 |
invokerRootPane.setFocusTraversalKeysEnabled(false); |
|
1208 |
||
1209 |
menuInputMap = getInputMap(popup, invokerRootPane); |
|
1210 |
addUIInputMap(invokerRootPane, menuInputMap); |
|
1211 |
addUIActionMap(invokerRootPane, menuActionMap); |
|
1212 |
} |
|
1213 |
} else if (lastPathSelected.length != 0 && p.length == 0) { |
|
1214 |
// menu hidden -- return focus to where it had been before |
|
1215 |
// and uninstall menu keybindings |
|
1216 |
removeItems(); |
|
1217 |
} else { |
|
1218 |
if (popup != lastPopup) { |
|
1219 |
receivedKeyPressed = false; |
|
1220 |
} |
|
1221 |
} |
|
1222 |
||
1223 |
// Remember the last path selected |
|
1224 |
lastPathSelected = p; |
|
1225 |
lastPopup = popup; |
|
1226 |
} |
|
1227 |
||
1228 |
public void keyPressed(KeyEvent ev) { |
|
1229 |
receivedKeyPressed = true; |
|
1230 |
MenuSelectionManager.defaultManager().processKeyEvent(ev); |
|
1231 |
} |
|
1232 |
||
1233 |
public void keyReleased(KeyEvent ev) { |
|
1234 |
if (receivedKeyPressed) { |
|
1235 |
receivedKeyPressed = false; |
|
1236 |
MenuSelectionManager.defaultManager().processKeyEvent(ev); |
|
1237 |
} |
|
1238 |
} |
|
1239 |
||
1240 |
public void keyTyped(KeyEvent ev) { |
|
1241 |
if (receivedKeyPressed) { |
|
1242 |
MenuSelectionManager.defaultManager().processKeyEvent(ev); |
|
1243 |
} |
|
1244 |
} |
|
1245 |
||
1246 |
void uninstall() { |
|
1247 |
synchronized (MENU_KEYBOARD_HELPER_KEY) { |
|
1248 |
MenuSelectionManager.defaultManager().removeChangeListener(this); |
|
1249 |
AppContext.getAppContext().remove(MENU_KEYBOARD_HELPER_KEY); |
|
1250 |
} |
|
1251 |
} |
|
1252 |
} |
|
1253 |
} |