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 */
25 package javax.swing;
26
27 import java.awt.*;
28 import java.util.*;
29 import java.awt.event.*;
30 import javax.swing.event.*;
31
32 import sun.awt.AppContext;
33
34 /**
35 * A MenuSelectionManager owns the selection in menu hierarchy.
36 *
37 * @author Arnaud Weber
38 */
39 public class MenuSelectionManager {
40 private Vector selection = new Vector();
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 Object MENU_SELECTION_MANAGER_KEY = new Object(); // javax.swing.MenuSelectionManager
48
49 /**
50 * Returns the default menu selection manager.
51 *
52 * @return a MenuSelectionManager object
53 */
54 public static MenuSelectionManager defaultManager() {
55 synchronized (MENU_SELECTION_MANAGER_KEY) {
56 AppContext context = AppContext.getAppContext();
57 MenuSelectionManager msm = (MenuSelectionManager)context.get(
58 MENU_SELECTION_MANAGER_KEY);
59 if (msm == null) {
60 msm = new MenuSelectionManager();
82 * feel engine and should not be called by client applications.
83 *
84 * @param path an array of <code>MenuElement</code> objects specifying
85 * the selected path
86 */
87 public void setSelectedPath(MenuElement[] path) {
88 int i,c;
89 int currentSelectionCount = selection.size();
90 int firstDifference = 0;
91
92 if(path == null) {
93 path = new MenuElement[0];
94 }
95
96 if (DEBUG) {
97 System.out.print("Previous: "); printMenuElementArray(getSelectedPath());
98 System.out.print("New: "); printMenuElementArray(path);
99 }
100
101 for(i=0,c=path.length;i<c;i++) {
102 if(i < currentSelectionCount && (MenuElement)selection.elementAt(i) == path[i])
103 firstDifference++;
104 else
105 break;
106 }
107
108 for(i=currentSelectionCount - 1 ; i >= firstDifference ; i--) {
109 MenuElement me = (MenuElement)selection.elementAt(i);
110 selection.removeElementAt(i);
111 me.menuSelectionChanged(false);
112 }
113
114 for(i = firstDifference, c = path.length ; i < c ; i++) {
115 if (path[i] != null) {
116 selection.addElement(path[i]);
117 path[i].menuSelectionChanged(true);
118 }
119 }
120
121 fireStateChanged();
122 }
123
124 /**
125 * Returns the path to the currently selected menu item
126 *
127 * @return an array of MenuElement objects representing the selected path
128 */
129 public MenuElement[] getSelectedPath() {
130 MenuElement res[] = new MenuElement[selection.size()];
131 int i,c;
132 for(i=0,c=selection.size();i<c;i++)
133 res[i] = (MenuElement) selection.elementAt(i);
134 return res;
135 }
136
137 /**
138 * Tell the menu selection to close and unselect all the menu components. Call this method
139 * when a choice has been made
140 */
141 public void clearSelectedPath() {
142 if (selection.size() > 0) {
143 setSelectedPath(null);
144 }
145 }
146
147 /**
148 * Adds a ChangeListener to the button.
149 *
150 * @param l the listener to add
151 */
152 public void addChangeListener(ChangeListener l) {
153 listenerList.add(ChangeListener.class, l);
154 }
155
156 /**
157 * Removes a ChangeListener from the button.
158 *
159 * @param l the listener to remove
160 */
161 public void removeChangeListener(ChangeListener l) {
162 listenerList.remove(ChangeListener.class, l);
163 }
164
165 /**
166 * Returns an array of all the <code>ChangeListener</code>s added
167 * to this MenuSelectionManager with addChangeListener().
168 *
169 * @return all of the <code>ChangeListener</code>s added or an empty
170 * array if no listeners have been added
171 * @since 1.4
172 */
173 public ChangeListener[] getChangeListeners() {
174 return (ChangeListener[])listenerList.getListeners(
175 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);
238 SwingUtilities.convertPointToScreen(p,source);
239
240 screenX = p.x;
241 screenY = p.y;
242
243 tmp = (Vector)selection.clone();
244 selectionSize = tmp.size();
245 boolean success = false;
246 for (i=selectionSize - 1;i >= 0 && success == false; i--) {
247 menuElement = (MenuElement) tmp.elementAt(i);
248 subElements = menuElement.getSubElements();
249
250 path = null;
251 for (j = 0, d = subElements.length;j < d && success == false; j++) {
252 if (subElements[j] == null)
253 continue;
254 mc = subElements[j].getComponent();
255 if(!mc.isShowing())
256 continue;
257 if(mc instanceof JComponent) {
258 cWidth = ((JComponent)mc).getWidth();
259 cHeight = ((JComponent)mc).getHeight();
260 } else {
261 r2 = mc.getBounds();
262 cWidth = r2.width;
263 cHeight = r2.height;
264 }
265 p.x = screenX;
266 p.y = screenY;
267 SwingUtilities.convertPointFromScreen(p,mc);
268
269 /** Send the event to visible menu element if menu element currently in
270 * the selected path or contains the event location
271 */
272 if(
273 (p.x >= 0 && p.x < cWidth && p.y >= 0 && p.y < cHeight)) {
274 int k;
275 if(path == null) {
276 path = new MenuElement[i+2];
277 for(k=0;k<=i;k++)
278 path[k] = (MenuElement)tmp.elementAt(k);
279 }
318 event.isPopupTrigger(),
319 MouseEvent.NOBUTTON);
320 subElements[j].processMouseEvent(mouseEvent, path, this);
321 success = true;
322 event.consume();
323 }
324 }
325 }
326 }
327
328 private void printMenuElementArray(MenuElement path[]) {
329 printMenuElementArray(path, false);
330 }
331
332 private void printMenuElementArray(MenuElement path[], boolean dumpStack) {
333 System.out.println("Path is(");
334 int i, j;
335 for(i=0,j=path.length; i<j ;i++){
336 for (int k=0; k<=i; k++)
337 System.out.print(" ");
338 MenuElement me = (MenuElement) path[i];
339 if(me instanceof JMenuItem) {
340 System.out.println(((JMenuItem)me).getText() + ", ");
341 } else if (me instanceof JMenuBar) {
342 System.out.println("JMenuBar, ");
343 } else if(me instanceof JPopupMenu) {
344 System.out.println("JPopupMenu, ");
345 } else if (me == null) {
346 System.out.println("NULL , ");
347 } else {
348 System.out.println("" + me + ", ");
349 }
350 }
351 System.out.println(")");
352
353 if (dumpStack == true)
354 Thread.dumpStack();
355 }
356
357 /**
358 * Returns the component in the currently selected path
379 int selectionSize;
380
381 SwingUtilities.convertPointToScreen(p,source);
382
383 screenX = p.x;
384 screenY = p.y;
385
386 tmp = (Vector)selection.clone();
387 selectionSize = tmp.size();
388 for(i=selectionSize - 1 ; i >= 0 ; i--) {
389 menuElement = (MenuElement) tmp.elementAt(i);
390 subElements = menuElement.getSubElements();
391
392 for(j = 0, d = subElements.length ; j < d ; j++) {
393 if (subElements[j] == null)
394 continue;
395 mc = subElements[j].getComponent();
396 if(!mc.isShowing())
397 continue;
398 if(mc instanceof JComponent) {
399 cWidth = ((JComponent)mc).getWidth();
400 cHeight = ((JComponent)mc).getHeight();
401 } else {
402 r2 = mc.getBounds();
403 cWidth = r2.width;
404 cHeight = r2.height;
405 }
406 p.x = screenX;
407 p.y = screenY;
408 SwingUtilities.convertPointFromScreen(p,mc);
409
410 /** Return the deepest component on the selection
411 * path in whose bounds the event's point occurs
412 */
413 if (p.x >= 0 && p.x < cWidth && p.y >= 0 && p.y < cHeight) {
414 return mc;
415 }
416 }
417 }
418 return null;
419 }
420
421 /**
422 * When a MenuElement receives an event from a KeyListener, it should never process the event
423 * directly. Instead all MenuElements should call this method with the event.
424 *
425 * @param e a KeyEvent object
426 */
427 public void processKeyEvent(KeyEvent e) {
428 MenuElement[] sel2 = new MenuElement[0];
429 sel2 = (MenuElement[])selection.toArray(sel2);
430 int selSize = sel2.length;
431 MenuElement[] path;
432
433 if (selSize < 1) {
434 return;
435 }
436
437 for (int i=selSize-1; i>=0; i--) {
438 MenuElement elem = sel2[i];
439 MenuElement[] subs = elem.getSubElements();
440 path = null;
441
442 for (int j=0; j<subs.length; j++) {
443 if (subs[j] == null || !subs[j].getComponent().isShowing()
444 || !subs[j].getComponent().isEnabled()) {
445 continue;
446 }
447
448 if(path == null) {
449 path = new MenuElement[i+2];
454 if (e.isConsumed()) {
455 return;
456 }
457 }
458 }
459
460 // finally dispatch event to the first component in path
461 path = new MenuElement[1];
462 path[0] = sel2[0];
463 path[0].processKeyEvent(e, path, this);
464 if (e.isConsumed()) {
465 return;
466 }
467 }
468
469 /**
470 * Return true if c is part of the currently used menu
471 */
472 public boolean isComponentPartOfCurrentMenu(Component c) {
473 if(selection.size() > 0) {
474 MenuElement me = (MenuElement)selection.elementAt(0);
475 return isComponentPartOfCurrentMenu(me,c);
476 } else
477 return false;
478 }
479
480 private boolean isComponentPartOfCurrentMenu(MenuElement root,Component c) {
481 MenuElement children[];
482 int i,d;
483
484 if (root == null)
485 return false;
486
487 if(root.getComponent() == c)
488 return true;
489 else {
490 children = root.getSubElements();
491 for(i=0,d=children.length;i<d;i++) {
492 if(isComponentPartOfCurrentMenu(children[i],c))
493 return true;
494 }
|
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 */
25 package javax.swing;
26
27 import java.awt.*;
28 import java.util.*;
29 import java.awt.event.*;
30 import javax.swing.event.*;
31
32 import sun.awt.AppContext;
33
34 /**
35 * A MenuSelectionManager owns the selection in menu hierarchy.
36 *
37 * @author Arnaud Weber
38 */
39 public 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 Object MENU_SELECTION_MANAGER_KEY = new Object(); // javax.swing.MenuSelectionManager
48
49 /**
50 * Returns the default menu selection manager.
51 *
52 * @return a MenuSelectionManager object
53 */
54 public static MenuSelectionManager defaultManager() {
55 synchronized (MENU_SELECTION_MANAGER_KEY) {
56 AppContext context = AppContext.getAppContext();
57 MenuSelectionManager msm = (MenuSelectionManager)context.get(
58 MENU_SELECTION_MANAGER_KEY);
59 if (msm == null) {
60 msm = new MenuSelectionManager();
82 * feel engine and should not be called by client applications.
83 *
84 * @param path an array of <code>MenuElement</code> objects specifying
85 * the selected path
86 */
87 public void setSelectedPath(MenuElement[] path) {
88 int i,c;
89 int currentSelectionCount = selection.size();
90 int firstDifference = 0;
91
92 if(path == null) {
93 path = new MenuElement[0];
94 }
95
96 if (DEBUG) {
97 System.out.print("Previous: "); printMenuElementArray(getSelectedPath());
98 System.out.print("New: "); printMenuElementArray(path);
99 }
100
101 for(i=0,c=path.length;i<c;i++) {
102 if (i < currentSelectionCount && selection.elementAt(i) == path[i])
103 firstDifference++;
104 else
105 break;
106 }
107
108 for(i=currentSelectionCount - 1 ; i >= firstDifference ; i--) {
109 MenuElement me = selection.elementAt(i);
110 selection.removeElementAt(i);
111 me.menuSelectionChanged(false);
112 }
113
114 for(i = firstDifference, c = path.length ; i < c ; i++) {
115 if (path[i] != null) {
116 selection.addElement(path[i]);
117 path[i].menuSelectionChanged(true);
118 }
119 }
120
121 fireStateChanged();
122 }
123
124 /**
125 * Returns the path to the currently selected menu item
126 *
127 * @return an array of MenuElement objects representing the selected path
128 */
129 public MenuElement[] getSelectedPath() {
130 MenuElement res[] = new MenuElement[selection.size()];
131 int i,c;
132 for(i=0,c=selection.size();i<c;i++)
133 res[i] = selection.elementAt(i);
134 return res;
135 }
136
137 /**
138 * Tell the menu selection to close and unselect all the menu components. Call this method
139 * when a choice has been made
140 */
141 public void clearSelectedPath() {
142 if (selection.size() > 0) {
143 setSelectedPath(null);
144 }
145 }
146
147 /**
148 * Adds a ChangeListener to the button.
149 *
150 * @param l the listener to add
151 */
152 public void addChangeListener(ChangeListener l) {
153 listenerList.add(ChangeListener.class, l);
154 }
155
156 /**
157 * Removes a ChangeListener from the button.
158 *
159 * @param l the listener to remove
160 */
161 public void removeChangeListener(ChangeListener l) {
162 listenerList.remove(ChangeListener.class, l);
163 }
164
165 /**
166 * Returns an array of all the <code>ChangeListener</code>s added
167 * to this MenuSelectionManager with addChangeListener().
168 *
169 * @return all of the <code>ChangeListener</code>s added or an empty
170 * array if no listeners have been added
171 * @since 1.4
172 */
173 public ChangeListener[] getChangeListeners() {
174 return listenerList.getListeners(ChangeListener.class);
175 }
176
177 /**
178 * Notifies all listeners that have registered interest for
179 * notification on this event type. The event instance
180 * is created lazily.
181 *
182 * @see EventListenerList
183 */
184 protected void fireStateChanged() {
185 // Guaranteed to return a non-null array
186 Object[] listeners = listenerList.getListenerList();
187 // Process the listeners last to first, notifying
188 // those that are interested in this event
189 for (int i = listeners.length-2; i>=0; i-=2) {
190 if (listeners[i]==ChangeListener.class) {
191 // Lazily create the event:
192 if (changeEvent == null)
193 changeEvent = new ChangeEvent(this);
194 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
237 SwingUtilities.convertPointToScreen(p,source);
238
239 screenX = p.x;
240 screenY = p.y;
241
242 tmp = (Vector)selection.clone();
243 selectionSize = tmp.size();
244 boolean success = false;
245 for (i=selectionSize - 1;i >= 0 && success == false; i--) {
246 menuElement = (MenuElement) tmp.elementAt(i);
247 subElements = menuElement.getSubElements();
248
249 path = null;
250 for (j = 0, d = subElements.length;j < d && success == false; j++) {
251 if (subElements[j] == null)
252 continue;
253 mc = subElements[j].getComponent();
254 if(!mc.isShowing())
255 continue;
256 if(mc instanceof JComponent) {
257 cWidth = mc.getWidth();
258 cHeight = mc.getHeight();
259 } else {
260 r2 = mc.getBounds();
261 cWidth = r2.width;
262 cHeight = r2.height;
263 }
264 p.x = screenX;
265 p.y = screenY;
266 SwingUtilities.convertPointFromScreen(p,mc);
267
268 /** Send the event to visible menu element if menu element currently in
269 * the selected path or contains the event location
270 */
271 if(
272 (p.x >= 0 && p.x < cWidth && p.y >= 0 && p.y < cHeight)) {
273 int k;
274 if(path == null) {
275 path = new MenuElement[i+2];
276 for(k=0;k<=i;k++)
277 path[k] = (MenuElement)tmp.elementAt(k);
278 }
317 event.isPopupTrigger(),
318 MouseEvent.NOBUTTON);
319 subElements[j].processMouseEvent(mouseEvent, path, this);
320 success = true;
321 event.consume();
322 }
323 }
324 }
325 }
326
327 private void printMenuElementArray(MenuElement path[]) {
328 printMenuElementArray(path, false);
329 }
330
331 private void printMenuElementArray(MenuElement path[], boolean dumpStack) {
332 System.out.println("Path is(");
333 int i, j;
334 for(i=0,j=path.length; i<j ;i++){
335 for (int k=0; k<=i; k++)
336 System.out.print(" ");
337 MenuElement me = path[i];
338 if(me instanceof JMenuItem) {
339 System.out.println(((JMenuItem)me).getText() + ", ");
340 } else if (me instanceof JMenuBar) {
341 System.out.println("JMenuBar, ");
342 } else if(me instanceof JPopupMenu) {
343 System.out.println("JPopupMenu, ");
344 } else if (me == null) {
345 System.out.println("NULL , ");
346 } else {
347 System.out.println("" + me + ", ");
348 }
349 }
350 System.out.println(")");
351
352 if (dumpStack == true)
353 Thread.dumpStack();
354 }
355
356 /**
357 * Returns the component in the currently selected path
378 int selectionSize;
379
380 SwingUtilities.convertPointToScreen(p,source);
381
382 screenX = p.x;
383 screenY = p.y;
384
385 tmp = (Vector)selection.clone();
386 selectionSize = tmp.size();
387 for(i=selectionSize - 1 ; i >= 0 ; i--) {
388 menuElement = (MenuElement) tmp.elementAt(i);
389 subElements = menuElement.getSubElements();
390
391 for(j = 0, d = subElements.length ; j < d ; j++) {
392 if (subElements[j] == null)
393 continue;
394 mc = subElements[j].getComponent();
395 if(!mc.isShowing())
396 continue;
397 if(mc instanceof JComponent) {
398 cWidth = mc.getWidth();
399 cHeight = mc.getHeight();
400 } else {
401 r2 = mc.getBounds();
402 cWidth = r2.width;
403 cHeight = r2.height;
404 }
405 p.x = screenX;
406 p.y = screenY;
407 SwingUtilities.convertPointFromScreen(p,mc);
408
409 /** Return the deepest component on the selection
410 * path in whose bounds the event's point occurs
411 */
412 if (p.x >= 0 && p.x < cWidth && p.y >= 0 && p.y < cHeight) {
413 return mc;
414 }
415 }
416 }
417 return null;
418 }
419
420 /**
421 * When a MenuElement receives an event from a KeyListener, it should never process the event
422 * directly. Instead all MenuElements should call this method with the event.
423 *
424 * @param e a KeyEvent object
425 */
426 public void processKeyEvent(KeyEvent e) {
427 MenuElement[] sel2 = new MenuElement[0];
428 sel2 = selection.toArray(sel2);
429 int selSize = sel2.length;
430 MenuElement[] path;
431
432 if (selSize < 1) {
433 return;
434 }
435
436 for (int i=selSize-1; i>=0; i--) {
437 MenuElement elem = sel2[i];
438 MenuElement[] subs = elem.getSubElements();
439 path = null;
440
441 for (int j=0; j<subs.length; j++) {
442 if (subs[j] == null || !subs[j].getComponent().isShowing()
443 || !subs[j].getComponent().isEnabled()) {
444 continue;
445 }
446
447 if(path == null) {
448 path = new MenuElement[i+2];
453 if (e.isConsumed()) {
454 return;
455 }
456 }
457 }
458
459 // finally dispatch event to the first component in path
460 path = new MenuElement[1];
461 path[0] = sel2[0];
462 path[0].processKeyEvent(e, path, this);
463 if (e.isConsumed()) {
464 return;
465 }
466 }
467
468 /**
469 * Return true if c is part of the currently used menu
470 */
471 public boolean isComponentPartOfCurrentMenu(Component c) {
472 if(selection.size() > 0) {
473 MenuElement me = selection.elementAt(0);
474 return isComponentPartOfCurrentMenu(me,c);
475 } else
476 return false;
477 }
478
479 private boolean isComponentPartOfCurrentMenu(MenuElement root,Component c) {
480 MenuElement children[];
481 int i,d;
482
483 if (root == null)
484 return false;
485
486 if(root.getComponent() == c)
487 return true;
488 else {
489 children = root.getSubElements();
490 for(i=0,d=children.length;i<d;i++) {
491 if(isComponentPartOfCurrentMenu(children[i],c))
492 return true;
493 }
|