History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/MenuSelectionManager.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/MenuSelectionManager.java+500−0
@@ -0,0 +1,500 @@
1/*
2 * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
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
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
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 *
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.
24 */
25package javax.swing;
26
27import java.awt.*;
28import java.util.*;
29import java.awt.event.*;
30import javax.swing.event.*;
31
32import sun.awt.AppContext;
33
34/**
35 * A MenuSelectionManager owns the selection in menu hierarchy.
36 *
37 * @author Arnaud Weber
38 */
39public class MenuSelectionManager {
40 private Vector<MenuElement> selection = new Vector<MenuElement>();
41
42 /* diagnostic aids -- should be false for production builds. */
43 private static final boolean TRACE = false; // trace creates and disposes
44 private static final boolean VERBOSE = false; // show reuse hits/misses
45 private static final boolean DEBUG = false; // show bad params, misc.
46
47 private static final StringBuilder MENU_SELECTION_MANAGER_KEY =
48 new StringBuilder("javax.swing.MenuSelectionManager");
49
50 /**
51 * Returns the default menu selection manager.
52 *
53 * @return a MenuSelectionManager object
54 */
55 public static MenuSelectionManager defaultManager() {
56 synchronized (MENU_SELECTION_MANAGER_KEY) {
57 AppContext context = AppContext.getAppContext();
58 MenuSelectionManager msm = (MenuSelectionManager)context.get(
59 MENU_SELECTION_MANAGER_KEY);
60 if (msm == null) {
61 msm = new MenuSelectionManager();
62 context.put(MENU_SELECTION_MANAGER_KEY, msm);
63 }
64
65 return msm;
66 }
67 }
68
69 /**
70 * Only one ChangeEvent is needed per button model instance since the
71 * event's only state is the source property. The source of events
72 * generated is always "this".
73 */
74 protected transient ChangeEvent changeEvent = null;
75 protected EventListenerList listenerList = new EventListenerList();
76
77 /**
78 * Changes the selection in the menu hierarchy. The elements
79 * in the array are sorted in order from the root menu
80 * element to the currently selected menu element.
81 * <p>
82 * Note that this method is public but is used by the look and
83 * feel engine and should not be called by client applications.
84 *
85 * @param path an array of <code>MenuElement</code> objects specifying
86 * the selected path
87 */
88 public void setSelectedPath(MenuElement[] path) {
89 int i,c;
90 int currentSelectionCount = selection.size();
91 int firstDifference = 0;
92
93 if(path == null) {
94 path = new MenuElement[0];
95 }
96
97 if (DEBUG) {
98 System.out.print("Previous: "); printMenuElementArray(getSelectedPath());
99 System.out.print("New: "); printMenuElementArray(path);
100 }
101
102 for(i=0,c=path.length;i<c;i++) {
103 if (i < currentSelectionCount && selection.elementAt(i) == path[i])
104 firstDifference++;
105 else
106 break;
107 }
108
109 for(i=currentSelectionCount - 1 ; i >= firstDifference ; i--) {
110 MenuElement me = selection.elementAt(i);
111 selection.removeElementAt(i);
112 me.menuSelectionChanged(false);
113 }
114
115 for(i = firstDifference, c = path.length ; i < c ; i++) {
116 if (path[i] != null) {
117 selection.addElement(path[i]);
118 path[i].menuSelectionChanged(true);
119 }
120 }
121
122 fireStateChanged();
123 }
124
125 /**
126 * Returns the path to the currently selected menu item
127 *
128 * @return an array of MenuElement objects representing the selected path
129 */
130 public MenuElement[] getSelectedPath() {
131 MenuElement res[] = new MenuElement[selection.size()];
132 int i,c;
133 for(i=0,c=selection.size();i<c;i++)
134 res[i] = selection.elementAt(i);
135 return res;
136 }
137
138 /**
139 * Tell the menu selection to close and unselect all the menu components. Call this method
140 * when a choice has been made
141 */
142 public void clearSelectedPath() {
143 if (selection.size() > 0) {
144 setSelectedPath(null);
145 }
146 }
147
148 /**
149 * Adds a ChangeListener to the button.
150 *
151 * @param l the listener to add
152 */
153 public void addChangeListener(ChangeListener l) {
154 listenerList.add(ChangeListener.class, l);
155 }
156
157 /**
158 * Removes a ChangeListener from the button.
159 *
160 * @param l the listener to remove
161 */
162 public void removeChangeListener(ChangeListener l) {
163 listenerList.remove(ChangeListener.class, l);
164 }
165
166 /**
167 * Returns an array of all the <code>ChangeListener</code>s added
168 * to this MenuSelectionManager with addChangeListener().
169 *
170 * @return all of the <code>ChangeListener</code>s added or an empty
171 * array if no listeners have been added
172 * @since 1.4
173 */
174 public ChangeListener[] getChangeListeners() {
175 return listenerList.getListeners(ChangeListener.class);
176 }
177
178 /**
179 * Notifies all listeners that have registered interest for
180 * notification on this event type. The event instance
181 * is created lazily.
182 *
183 * @see EventListenerList
184 */
185 protected void fireStateChanged() {
186 // Guaranteed to return a non-null array
187 Object[] listeners = listenerList.getListenerList();
188 // Process the listeners last to first, notifying
189 // those that are interested in this event
190 for (int i = listeners.length-2; i>=0; i-=2) {
191 if (listeners[i]==ChangeListener.class) {
192 // Lazily create the event:
193 if (changeEvent == null)
194 changeEvent = new ChangeEvent(this);
195 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
196 }
197 }
198 }
199
200 /**
201 * When a MenuElement receives an event from a MouseListener, it should never process the event
202 * directly. Instead all MenuElements should call this method with the event.
203 *
204 * @param event a MouseEvent object
205 */
206 public void processMouseEvent(MouseEvent event) {
207 int screenX,screenY;
208 Point p;
209 int i,c,j,d;
210 Component mc;
211 Rectangle r2;
212 int cWidth,cHeight;
213 MenuElement menuElement;
214 MenuElement subElements[];
215 MenuElement path[];
216 Vector tmp;
217 int selectionSize;
218 p = event.getPoint();
219
220 Component source = event.getComponent();
221
222 if ((source != null) && !source.isShowing()) {
223 // This can happen if a mouseReleased removes the
224 // containing component -- bug 4146684
225 return;
226 }
227
228 int type = event.getID();
229 int modifiers = event.getModifiers();
230 // 4188027: drag enter/exit added in JDK 1.1.7A, JDK1.2
231 if ((type==MouseEvent.MOUSE_ENTERED||
232 type==MouseEvent.MOUSE_EXITED)
233 && ((modifiers & (InputEvent.BUTTON1_MASK |
234 InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK)) !=0 )) {
235 return;
236 }
237
238 if (source != null) {
239 SwingUtilities.convertPointToScreen(p, source);
240 }
241
242 screenX = p.x;
243 screenY = p.y;
244
245 tmp = (Vector)selection.clone();
246 selectionSize = tmp.size();
247 boolean success = false;
248 for (i=selectionSize - 1;i >= 0 && success == false; i--) {
249 menuElement = (MenuElement) tmp.elementAt(i);
250 subElements = menuElement.getSubElements();
251
252 path = null;
253 for (j = 0, d = subElements.length;j < d && success == false; j++) {
254 if (subElements[j] == null)
255 continue;
256 mc = subElements[j].getComponent();
257 if(!mc.isShowing())
258 continue;
259 if(mc instanceof JComponent) {
260 cWidth = mc.getWidth();
261 cHeight = mc.getHeight();
262 } else {
263 r2 = mc.getBounds();
264 cWidth = r2.width;
265 cHeight = r2.height;
266 }
267 p.x = screenX;
268 p.y = screenY;
269 SwingUtilities.convertPointFromScreen(p,mc);
270
271 /** Send the event to visible menu element if menu element currently in
272 * the selected path or contains the event location
273 */
274 if(
275 (p.x >= 0 && p.x < cWidth && p.y >= 0 && p.y < cHeight)) {
276 int k;
277 if(path == null) {
278 path = new MenuElement[i+2];
279 for(k=0;k<=i;k++)
280 path[k] = (MenuElement)tmp.elementAt(k);
281 }
282 path[i+1] = subElements[j];
283 MenuElement currentSelection[] = getSelectedPath();
284
285 // Enter/exit detection -- needs tuning...
286 if (currentSelection[currentSelection.length-1] !=
287 path[i+1] &&
288 (currentSelection.length < 2 ||
289 currentSelection[currentSelection.length-2] !=
290 path[i+1])) {
291 Component oldMC = currentSelection[currentSelection.length-1].getComponent();
292
293 MouseEvent exitEvent = new MouseEvent(oldMC, MouseEvent.MOUSE_EXITED,
294 event.getWhen(),
295 event.getModifiers(), p.x, p.y,
296 event.getXOnScreen(),
297 event.getYOnScreen(),
298 event.getClickCount(),
299 event.isPopupTrigger(),
300 MouseEvent.NOBUTTON);
301 currentSelection[currentSelection.length-1].
302 processMouseEvent(exitEvent, path, this);
303
304 MouseEvent enterEvent = new MouseEvent(mc,
305 MouseEvent.MOUSE_ENTERED,
306 event.getWhen(),
307 event.getModifiers(), p.x, p.y,
308 event.getXOnScreen(),
309 event.getYOnScreen(),
310 event.getClickCount(),
311 event.isPopupTrigger(),
312 MouseEvent.NOBUTTON);
313 subElements[j].processMouseEvent(enterEvent, path, this);
314 }
315 MouseEvent mouseEvent = new MouseEvent(mc, event.getID(),event. getWhen(),
316 event.getModifiers(), p.x, p.y,
317 event.getXOnScreen(),
318 event.getYOnScreen(),
319 event.getClickCount(),
320 event.isPopupTrigger(),
321 MouseEvent.NOBUTTON);
322 subElements[j].processMouseEvent(mouseEvent, path, this);
323 success = true;
324 event.consume();
325 }
326 }
327 }
328 }
329
330 private void printMenuElementArray(MenuElement path[]) {
331 printMenuElementArray(path, false);
332 }
333
334 private void printMenuElementArray(MenuElement path[], boolean dumpStack) {
335 System.out.println("Path is(");
336 int i, j;
337 for(i=0,j=path.length; i<j ;i++){
338 for (int k=0; k<=i; k++)
339 System.out.print(" ");
340 MenuElement me = path[i];
341 if(me instanceof JMenuItem) {
342 System.out.println(((JMenuItem)me).getText() + ", ");
343 } else if (me instanceof JMenuBar) {
344 System.out.println("JMenuBar, ");
345 } else if(me instanceof JPopupMenu) {
346 System.out.println("JPopupMenu, ");
347 } else if (me == null) {
348 System.out.println("NULL , ");
349 } else {
350 System.out.println("" + me + ", ");
351 }
352 }
353 System.out.println(")");
354
355 if (dumpStack == true)
356 Thread.dumpStack();
357 }
358
359 /**
360 * Returns the component in the currently selected path
361 * which contains sourcePoint.
362 *
363 * @param source The component in whose coordinate space sourcePoint
364 * is given
365 * @param sourcePoint The point which is being tested
366 * @return The component in the currently selected path which
367 * contains sourcePoint (relative to the source component's
368 * coordinate space. If sourcePoint is not inside a component
369 * on the currently selected path, null is returned.
370 */
371 public Component componentForPoint(Component source, Point sourcePoint) {
372 int screenX,screenY;
373 Point p = sourcePoint;
374 int i,c,j,d;
375 Component mc;
376 Rectangle r2;
377 int cWidth,cHeight;
378 MenuElement menuElement;
379 MenuElement subElements[];
380 Vector tmp;
381 int selectionSize;
382
383 SwingUtilities.convertPointToScreen(p,source);
384
385 screenX = p.x;
386 screenY = p.y;
387
388 tmp = (Vector)selection.clone();
389 selectionSize = tmp.size();
390 for(i=selectionSize - 1 ; i >= 0 ; i--) {
391 menuElement = (MenuElement) tmp.elementAt(i);
392 subElements = menuElement.getSubElements();
393
394 for(j = 0, d = subElements.length ; j < d ; j++) {
395 if (subElements[j] == null)
396 continue;
397 mc = subElements[j].getComponent();
398 if(!mc.isShowing())
399 continue;
400 if(mc instanceof JComponent) {
401 cWidth = mc.getWidth();
402 cHeight = mc.getHeight();
403 } else {
404 r2 = mc.getBounds();
405 cWidth = r2.width;
406 cHeight = r2.height;
407 }
408 p.x = screenX;
409 p.y = screenY;
410 SwingUtilities.convertPointFromScreen(p,mc);
411
412 /** Return the deepest component on the selection
413 * path in whose bounds the event's point occurs
414 */
415 if (p.x >= 0 && p.x < cWidth && p.y >= 0 && p.y < cHeight) {
416 return mc;
417 }
418 }
419 }
420 return null;
421 }
422
423 /**
424 * When a MenuElement receives an event from a KeyListener, it should never process the event
425 * directly. Instead all MenuElements should call this method with the event.
426 *
427 * @param e a KeyEvent object
428 */
429 public void processKeyEvent(KeyEvent e) {
430 MenuElement[] sel2 = new MenuElement[0];
431 sel2 = selection.toArray(sel2);
432 int selSize = sel2.length;
433 MenuElement[] path;
434
435 if (selSize < 1) {
436 return;
437 }
438
439 for (int i=selSize-1; i>=0; i--) {
440 MenuElement elem = sel2[i];
441 MenuElement[] subs = elem.getSubElements();
442 path = null;
443
444 for (int j=0; j<subs.length; j++) {
445 if (subs[j] == null || !subs[j].getComponent().isShowing()
446 || !subs[j].getComponent().isEnabled()) {
447 continue;
448 }
449
450 if(path == null) {
451 path = new MenuElement[i+2];
452 System.arraycopy(sel2, 0, path, 0, i+1);
453 }
454 path[i+1] = subs[j];
455 subs[j].processKeyEvent(e, path, this);
456 if (e.isConsumed()) {
457 return;
458 }
459 }
460 }
461
462 // finally dispatch event to the first component in path
463 path = new MenuElement[1];
464 path[0] = sel2[0];
465 path[0].processKeyEvent(e, path, this);
466 if (e.isConsumed()) {
467 return;
468 }
469 }
470
471 /**
472 * Return true if c is part of the currently used menu
473 */
474 public boolean isComponentPartOfCurrentMenu(Component c) {
475 if(selection.size() > 0) {
476 MenuElement me = selection.elementAt(0);
477 return isComponentPartOfCurrentMenu(me,c);
478 } else
479 return false;
480 }
481
482 private boolean isComponentPartOfCurrentMenu(MenuElement root,Component c) {
483 MenuElement children[];
484 int i,d;
485
486 if (root == null)
487 return false;
488
489 if(root.getComponent() == c)
490 return true;
491 else {
492 children = root.getSubElements();
493 for(i=0,d=children.length;i<d;i++) {
494 if(isComponentPartOfCurrentMenu(children[i],c))
495 return true;
496 }
497 }
498 return false;
499 }
500}