KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > plaf > basic > BasicMenuUI


1 /*
2  * @(#)BasicMenuUI.java 1.158 04/02/26
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.plaf.basic;
9
10 import sun.swing.DefaultLookup;
11 import sun.swing.UIAction;
12 import java.awt.*;
13 import java.awt.event.*;
14 import java.beans.*;
15 import javax.swing.*;
16 import javax.swing.event.*;
17 import javax.swing.plaf.*;
18 import javax.swing.border.*;
19 import java.util.Arrays JavaDoc;
20 import java.util.ArrayList JavaDoc;
21
22
23 /**
24  * A default L&F implementation of MenuUI. This implementation
25  * is a "combined" view/controller.
26  *
27  * @version 1.158 02/26/04
28  * @author Georges Saab
29  * @author David Karlton
30  * @author Arnaud Weber
31  */

32 public class BasicMenuUI extends BasicMenuItemUI JavaDoc
33 {
34     protected ChangeListener changeListener;
35     protected PropertyChangeListener propertyChangeListener;
36     protected MenuListener menuListener;
37
38     private int lastMnemonic = 0;
39
40     /** Uses as the parent of the windowInputMap when selected. */
41     private InputMap selectedWindowInputMap;
42
43     /* diagnostic aids -- should be false for production builds. */
44     private static final boolean TRACE = false; // trace creates and disposes
45
private static final boolean VERBOSE = false; // show reuse hits/misses
46
private static final boolean DEBUG = false; // show bad params, misc.
47

48     private static boolean crossMenuMnemonic = true;
49
50     public static ComponentUI createUI(JComponent x) {
51     return new BasicMenuUI JavaDoc();
52     }
53
54     static void loadActionMap(LazyActionMap JavaDoc map) {
55         BasicMenuItemUI.loadActionMap(map);
56         map.put(new Actions(Actions.SELECT, null, true));
57     }
58
59
60     protected void installDefaults() {
61     super.installDefaults();
62     updateDefaultBackgroundColor();
63     ((JMenu)menuItem).setDelay(200);
64         crossMenuMnemonic = UIManager.getBoolean("Menu.crossMenuMnemonic");
65     }
66
67     protected String JavaDoc getPropertyPrefix() {
68     return "Menu";
69     }
70
71     protected void installListeners() {
72     super.installListeners();
73
74     if (changeListener == null)
75         changeListener = createChangeListener(menuItem);
76
77     if (changeListener != null)
78         menuItem.addChangeListener(changeListener);
79
80     if (propertyChangeListener == null)
81         propertyChangeListener = createPropertyChangeListener(menuItem);
82
83     if (propertyChangeListener != null)
84         menuItem.addPropertyChangeListener(propertyChangeListener);
85         
86     if (menuListener == null)
87         menuListener = createMenuListener(menuItem);
88
89     if (menuListener != null)
90         ((JMenu)menuItem).addMenuListener(menuListener);
91     }
92
93     protected void installKeyboardActions() {
94     super.installKeyboardActions();
95     updateMnemonicBinding();
96     }
97
98     void installLazyActionMap() {
99         LazyActionMap.installLazyActionMap(menuItem, BasicMenuUI JavaDoc.class,
100                                            getPropertyPrefix() + ".actionMap");
101     }
102
103     void updateMnemonicBinding() {
104     int mnemonic = menuItem.getModel().getMnemonic();
105         int[] shortcutKeys = (int[])DefaultLookup.get(menuItem, this,
106                                                    "Menu.shortcutKeys");
107         if (shortcutKeys == null) {
108             shortcutKeys = new int[] {KeyEvent.ALT_MASK};
109         }
110     if (mnemonic == lastMnemonic) {
111         return;
112     }
113         InputMap windowInputMap = SwingUtilities.getUIInputMap(
114                        menuItem, JComponent.WHEN_IN_FOCUSED_WINDOW);
115     if (lastMnemonic != 0 && windowInputMap != null) {
116             for (int i=0; i<shortcutKeys.length; i++) {
117                 windowInputMap.remove(KeyStroke.getKeyStroke
118                                       (lastMnemonic, shortcutKeys[i], false));
119             }
120     }
121     if (mnemonic != 0) {
122         if (windowInputMap == null) {
123         windowInputMap = createInputMap(JComponent.
124                           WHEN_IN_FOCUSED_WINDOW);
125         SwingUtilities.replaceUIInputMap(menuItem, JComponent.
126                        WHEN_IN_FOCUSED_WINDOW, windowInputMap);
127         }
128             for (int i=0; i<shortcutKeys.length; i++) {
129                 windowInputMap.put(KeyStroke.getKeyStroke(mnemonic,
130                                          shortcutKeys[i], false),
131                                    "selectMenu");
132             }
133         }
134     lastMnemonic = mnemonic;
135     }
136
137     protected void uninstallKeyboardActions() {
138     super.uninstallKeyboardActions();
139         lastMnemonic = 0;
140     }
141
142     protected MouseInputListener createMouseInputListener(JComponent c) {
143     return getHandler();
144     }
145
146     protected MenuListener createMenuListener(JComponent c) {
147     return null;
148     }
149
150     protected ChangeListener createChangeListener(JComponent c) {
151     return null;
152     }
153
154     protected PropertyChangeListener createPropertyChangeListener(JComponent c) {
155         return getHandler();
156     }
157
158     BasicMenuItemUI.Handler JavaDoc getHandler() {
159         if (handler == null) {
160             handler = new Handler();
161         }
162         return handler;
163     }
164
165     protected void uninstallDefaults() {
166     menuItem.setArmed(false);
167     menuItem.setSelected(false);
168     menuItem.resetKeyboardActions();
169     super.uninstallDefaults();
170     }
171
172     protected void uninstallListeners() {
173     super.uninstallListeners();
174
175     if (changeListener != null)
176         menuItem.removeChangeListener(changeListener);
177
178     if (propertyChangeListener != null)
179         menuItem.removePropertyChangeListener(propertyChangeListener);
180
181     if (menuListener != null)
182         ((JMenu)menuItem).removeMenuListener(menuListener);
183
184     changeListener = null;
185     propertyChangeListener = null;
186     menuListener = null;
187         handler = null;
188     }
189
190     protected MenuDragMouseListener createMenuDragMouseListener(JComponent c) {
191     return getHandler();
192     }
193     
194     protected MenuKeyListener createMenuKeyListener(JComponent c) {
195     return (MenuKeyListener)getHandler();
196     }
197
198     public Dimension getMaximumSize(JComponent c) {
199     if (((JMenu)menuItem).isTopLevelMenu() == true) {
200         Dimension d = c.getPreferredSize();
201         return new Dimension(d.width, Short.MAX_VALUE);
202     }
203         return null;
204     }
205
206     protected void setupPostTimer(JMenu menu) {
207         Timer timer = new Timer(menu.getDelay(), new Actions(
208                                     Actions.SELECT, menu,false));
209         timer.setRepeats(false);
210         timer.start();
211     }
212
213     private static void appendPath(MenuElement[] path, MenuElement elem) {
214         MenuElement newPath[] = new MenuElement[path.length+1];
215         System.arraycopy(path, 0, newPath, 0, path.length);
216         newPath[path.length] = elem;
217         MenuSelectionManager.defaultManager().setSelectedPath(newPath);
218     }
219
220     private static class Actions extends UIAction {
221         private static final String JavaDoc SELECT = "selectMenu";
222
223         // NOTE: This will be null if the action is registered in the
224
// ActionMap. For the timer use it will be non-null.
225
private JMenu menu;
226         private boolean force=false;
227
228         Actions(String JavaDoc key, JMenu menu, boolean shouldForce) {
229             super(key);
230         this.menu = menu;
231             this.force = shouldForce;
232     }
233     
234         private JMenu getMenu(ActionEvent e) {
235             if (e.getSource() instanceof JMenu) {
236                 return (JMenu)e.getSource();
237             }
238             return menu;
239         }
240
241     public void actionPerformed(ActionEvent e) {
242             JMenu menu = getMenu(e);
243             if (!crossMenuMnemonic) {
244                 JPopupMenu pm = BasicPopupMenuUI.getLastPopup();
245                 if (pm != null && pm != menu.getParent()) {
246                     return;
247                 }
248             }
249
250         final MenuSelectionManager defaultManager = MenuSelectionManager.defaultManager();
251             if(force) {
252                 Container cnt = menu.getParent();
253                 if(cnt != null && cnt instanceof JMenuBar) {
254                     MenuElement me[];
255                     MenuElement subElements[];
256             
257                     subElements = menu.getPopupMenu().getSubElements();
258                     if(subElements.length > 0) {
259                         me = new MenuElement[4];
260                         me[0] = (MenuElement) cnt;
261                         me[1] = (MenuElement) menu;
262                         me[2] = (MenuElement) menu.getPopupMenu();
263                         me[3] = subElements[0];
264                     } else {
265                         me = new MenuElement[3];
266                         me[0] = (MenuElement)cnt;
267                         me[1] = menu;
268                         me[2] = (MenuElement) menu.getPopupMenu();
269                     }
270                     defaultManager.setSelectedPath(me);
271         }
272             } else {
273                 MenuElement path[] = defaultManager.getSelectedPath();
274                 if(path.length > 0 && path[path.length-1] == menu) {
275                     appendPath(path, menu.getPopupMenu());
276                 }
277             }
278         }
279
280     public boolean isEnabled(Object JavaDoc c) {
281             if (c instanceof JMenu) {
282                 return ((JMenu)c).isEnabled();
283             }
284             return true;
285     }
286     }
287
288     /*
289      * Set the background color depending on whether this is a toplevel menu
290      * in a menubar or a submenu of another menu.
291      */

292     private void updateDefaultBackgroundColor() {
293     if (!UIManager.getBoolean("Menu.useMenuBarBackgroundForTopLevel")) {
294        return;
295     }
296     JMenu menu = (JMenu)menuItem;
297     if (menu.getBackground() instanceof UIResource) {
298         if (menu.isTopLevelMenu()) {
299         menu.setBackground(UIManager.getColor("MenuBar.background"));
300         } else {
301         menu.setBackground(UIManager.getColor(getPropertyPrefix() + ".background"));
302         }
303     }
304     }
305
306     /**
307      * Instantiated and used by a menu item to handle the current menu selection
308      * from mouse events. A MouseInputHandler processes and forwards all mouse events
309      * to a shared instance of the MenuSelectionManager.
310      * <p>
311      * This class is protected so that it can be subclassed by other look and
312      * feels to implement their own mouse handling behavior. All overridden
313      * methods should call the parent methods so that the menu selection
314      * is correct.
315      *
316      * @see javax.swing.MenuSelectionManager
317      * @since 1.4
318      */

319     protected class MouseInputHandler implements MouseInputListener {
320         // NOTE: This class exists only for backward compatability. All
321
// its functionality has been moved into Handler. If you need to add
322
// new functionality add it to the Handler, but make sure this
323
// class calls into the Handler.
324

325     public void mouseClicked(MouseEvent e) {
326             getHandler().mouseClicked(e);
327         }
328
329     /**
330      * Invoked when the mouse has been clicked on the menu. This
331      * method clears or sets the selection path of the
332      * MenuSelectionManager.
333      *
334      * @param e the mouse event
335      */

336         public void mousePressed(MouseEvent e) {
337             getHandler().mousePressed(e);
338         }
339
340     /**
341      * Invoked when the mouse has been released on the menu. Delegates the
342      * mouse event to the MenuSelectionManager.
343      *
344      * @param e the mouse event
345      */

346     public void mouseReleased(MouseEvent e) {
347             getHandler().mouseReleased(e);
348     }
349
350     /**
351      * Invoked when the cursor enters the menu. This method sets the selected
352      * path for the MenuSelectionManager and handles the case
353      * in which a menu item is used to pop up an additional menu, as in a
354      * hierarchical menu system.
355      *
356      * @param e the mouse event; not used
357      */

358     public void mouseEntered(MouseEvent e) {
359             getHandler().mouseEntered(e);
360     }
361     public void mouseExited(MouseEvent e) {
362             getHandler().mouseExited(e);
363     }
364     
365     /**
366      * Invoked when a mouse button is pressed on the menu and then dragged.
367      * Delegates the mouse event to the MenuSelectionManager.
368      *
369      * @param e the mouse event
370      * @see java.awt.event.MouseMotionListener#mouseDragged
371      */

372     public void mouseDragged(MouseEvent e) {
373             getHandler().mouseDragged(e);
374     }
375
376     public void mouseMoved(MouseEvent e) {
377             getHandler().mouseMoved(e);
378     }
379     }
380
381     /**
382      * As of Java 2 platform 1.4, this previously undocumented class
383      * is now obsolete. KeyBindings are now managed by the popup menu.
384      */

385     public class ChangeHandler implements ChangeListener {
386         public JMenu menu;
387     public BasicMenuUI JavaDoc ui;
388         public boolean isSelected = false;
389         public Component wasFocused;
390
391         public ChangeHandler(JMenu m, BasicMenuUI JavaDoc ui) {
392             menu = m;
393             this.ui = ui;
394         }
395
396         public void stateChanged(ChangeEvent e) { }
397     }
398
399     private class Handler extends BasicMenuItemUI.Handler JavaDoc implements
400             MenuKeyListener {
401         //
402
// PropertyChangeListener
403
//
404
public void propertyChange(PropertyChangeEvent e) {
405         if (e.getPropertyName() == AbstractButton.
406                              MNEMONIC_CHANGED_PROPERTY) {
407                 updateMnemonicBinding();
408         }
409             else {
410         if (e.getPropertyName().equals("ancestor")) {
411             updateDefaultBackgroundColor();
412             }
413                 super.propertyChange(e);
414             }
415     }
416
417         //
418
// MouseInputListener
419
//
420
public void mouseClicked(MouseEvent e) {
421         }
422
423     /**
424      * Invoked when the mouse has been clicked on the menu. This
425      * method clears or sets the selection path of the
426      * MenuSelectionManager.
427      *
428      * @param e the mouse event
429      */

430         public void mousePressed(MouseEvent e) {
431         JMenu menu = (JMenu)menuItem;
432         if (!menu.isEnabled())
433         return;
434
435         MenuSelectionManager manager =
436         MenuSelectionManager.defaultManager();
437             if(menu.isTopLevelMenu()) {
438         if(menu.isSelected()) {
439             manager.clearSelectedPath();
440         } else {
441             Container cnt = menu.getParent();
442             if(cnt != null && cnt instanceof JMenuBar) {
443             MenuElement me[] = new MenuElement[2];
444             me[0]=(MenuElement)cnt;
445             me[1]=menu;
446             manager.setSelectedPath(me);
447             }
448         }
449         }
450
451             MenuElement selectedPath[] = manager.getSelectedPath();
452             if (selectedPath.length > 0 &&
453                 selectedPath[selectedPath.length-1] != menu.getPopupMenu()) {
454
455         if(menu.isTopLevelMenu() ||
456            menu.getDelay() == 0) {
457                     appendPath(selectedPath, menu.getPopupMenu());
458         } else {
459             setupPostTimer(menu);
460         }
461             }
462         }
463
464     /**
465      * Invoked when the mouse has been released on the menu. Delegates the
466      * mouse event to the MenuSelectionManager.
467      *
468      * @param e the mouse event
469      */

470     public void mouseReleased(MouseEvent e) {
471         JMenu menu = (JMenu)menuItem;
472         if (!menu.isEnabled())
473         return;
474         MenuSelectionManager manager =
475         MenuSelectionManager.defaultManager();
476         manager.processMouseEvent(e);
477         if (!e.isConsumed())
478         manager.clearSelectedPath();
479     }
480
481     /**
482      * Invoked when the cursor enters the menu. This method sets the selected
483      * path for the MenuSelectionManager and handles the case
484      * in which a menu item is used to pop up an additional menu, as in a
485      * hierarchical menu system.
486      *
487      * @param e the mouse event; not used
488      */

489     public void mouseEntered(MouseEvent e) {
490         JMenu menu = (JMenu)menuItem;
491         if (!menu.isEnabled())
492         return;
493
494         MenuSelectionManager manager =
495         MenuSelectionManager.defaultManager();
496         MenuElement selectedPath[] = manager.getSelectedPath();
497         if (!menu.isTopLevelMenu()) {
498         if(!(selectedPath.length > 0 &&
499              selectedPath[selectedPath.length-1] ==
500              menu.getPopupMenu())) {
501             if(menu.getDelay() == 0) {
502                         appendPath(getPath(), menu.getPopupMenu());
503                     } else {
504             manager.setSelectedPath(getPath());
505             setupPostTimer(menu);
506             }
507         }
508         } else {
509         if(selectedPath.length > 0 &&
510            selectedPath[0] == menu.getParent()) {
511             MenuElement newPath[] = new MenuElement[3];
512             // A top level menu's parent is by definition
513
// a JMenuBar
514
newPath[0] = (MenuElement)menu.getParent();
515             newPath[1] = menu;
516             newPath[2] = menu.getPopupMenu();
517             manager.setSelectedPath(newPath);
518         }
519         }
520     }
521     public void mouseExited(MouseEvent e) {
522     }
523     
524     /**
525      * Invoked when a mouse button is pressed on the menu and then dragged.
526      * Delegates the mouse event to the MenuSelectionManager.
527      *
528      * @param e the mouse event
529      * @see java.awt.event.MouseMotionListener#mouseDragged
530      */

531     public void mouseDragged(MouseEvent e) {
532         JMenu menu = (JMenu)menuItem;
533         if (!menu.isEnabled())
534         return;
535         MenuSelectionManager.defaultManager().processMouseEvent(e);
536     }
537     public void mouseMoved(MouseEvent e) {
538     }
539
540
541         //
542
// MenuDragHandler
543
//
544
public void menuDragMouseEntered(MenuDragMouseEvent e) {}
545     public void menuDragMouseDragged(MenuDragMouseEvent e) {
546         if (menuItem.isEnabled() == false)
547         return;
548         
549         MenuSelectionManager manager = e.getMenuSelectionManager();
550         MenuElement path[] = e.getPath();
551         
552         Point p = e.getPoint();
553         if(p.x >= 0 && p.x < menuItem.getWidth() &&
554            p.y >= 0 && p.y < menuItem.getHeight()) {
555         JMenu menu = (JMenu)menuItem;
556         MenuElement selectedPath[] = manager.getSelectedPath();
557         if(!(selectedPath.length > 0 &&
558              selectedPath[selectedPath.length-1] ==
559              menu.getPopupMenu())) {
560             if(menu.isTopLevelMenu() ||
561                menu.getDelay() == 0 ||
562                e.getID() == MouseEvent.MOUSE_DRAGGED) {
563                         appendPath(path, menu.getPopupMenu());
564             } else {
565             manager.setSelectedPath(path);
566             setupPostTimer(menu);
567             }
568         }
569         } else if(e.getID() == MouseEvent.MOUSE_RELEASED) {
570         Component comp = manager.componentForPoint(e.getComponent(), e.getPoint());
571         if (comp == null)
572             manager.clearSelectedPath();
573         }
574         
575     }
576     public void menuDragMouseExited(MenuDragMouseEvent e) {}
577     public void menuDragMouseReleased(MenuDragMouseEvent e) {}
578
579
580         //
581
// MenuKeyListener
582
//
583
/**
584      * Open the Menu
585      */

586     public void menuKeyTyped(MenuKeyEvent e) {
587             if (!crossMenuMnemonic && BasicPopupMenuUI.getLastPopup() != null) {
588                 // when crossMenuMnemonic is not set, we don't open a toplevel
589
// menu if another toplevel menu is already open
590
return;
591                 }
592
593             char key = Character.toLowerCase((char)menuItem.getMnemonic());
594             MenuElement path[] = e.getPath();
595             if (key == Character.toLowerCase(e.getKeyChar())) {
596                 JPopupMenu popupMenu = ((JMenu)menuItem).getPopupMenu();
597                 ArrayList JavaDoc newList = new ArrayList JavaDoc(Arrays.asList(path));
598                 newList.add(popupMenu);
599                 MenuElement subs[] = popupMenu.getSubElements();
600                 MenuElement sub =
601                         BasicPopupMenuUI.findEnabledChild(subs, -1, true);
602                 if(sub != null) {
603                     newList.add(sub);
604                 }
605                 MenuSelectionManager manager = e.getMenuSelectionManager();
606                 MenuElement newPath[] = new MenuElement[0];;
607                 newPath = (MenuElement[]) newList.toArray(newPath);
608                 manager.setSelectedPath(newPath);
609                 e.consume();
610             }
611         }
612
613         public void menuKeyPressed(MenuKeyEvent e) {}
614     public void menuKeyReleased(MenuKeyEvent e) {}
615     }
616 }
617
Popular Tags