KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > JMenuBar


1 /*
2  * @(#)JMenuBar.java 1.98 04/05/18
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;
9
10 import java.awt.Component JavaDoc;
11 import java.awt.Dimension JavaDoc;
12 import java.awt.Graphics JavaDoc;
13 import java.awt.Insets JavaDoc;
14 import java.awt.Point JavaDoc;
15 import java.awt.Rectangle JavaDoc;
16 import java.awt.event.*;
17 import java.util.Vector JavaDoc;
18 import java.util.Enumeration JavaDoc;
19
20 import java.io.Serializable JavaDoc;
21 import java.io.ObjectOutputStream JavaDoc;
22 import java.io.ObjectInputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24
25 import javax.swing.event.*;
26 import javax.swing.border.Border JavaDoc;
27 import javax.swing.plaf.*;
28 import javax.accessibility.*;
29
30 /**
31  * An implementation of a menu bar. You add <code>JMenu</code> objects to the
32  * menu bar to construct a menu. When the user selects a <code>JMenu</code>
33  * object, its associated <code>JPopupMenu</code> is displayed, allowing the
34  * user to select one of the <code>JMenuItems</code> on it.
35  * <p>
36  * For information and examples of using menu bars see
37  * <a
38  href="http://java.sun.com/docs/books/tutorial/uiswing/components/menu.html">How to Use Menus</a>,
39  * a section in <em>The Java Tutorial.</em>
40  * <p>
41  * <strong>Warning:</strong>
42  * Serialized objects of this class will not be compatible with
43  * future Swing releases. The current serialization support is
44  * appropriate for short term storage or RMI between applications running
45  * the same version of Swing. As of 1.4, support for long term storage
46  * of all JavaBeans<sup><font size="-2">TM</font></sup>
47  * has been added to the <code>java.beans</code> package.
48  * Please see {@link java.beans.XMLEncoder}.
49  *
50  * @beaninfo
51  * attribute: isContainer true
52  * description: A container for holding and displaying menus.
53  *
54  * @version 1.98 05/18/04
55  * @author Georges Saab
56  * @author David Karlton
57  * @author Arnaud Weber
58  * @see JMenu
59  * @see JPopupMenu
60  * @see JMenuItem
61  */

62 public class JMenuBar extends JComponent JavaDoc implements Accessible,MenuElement JavaDoc
63 {
64     /**
65      * @see #getUIClassID
66      * @see #readObject
67      */

68     private static final String JavaDoc uiClassID = "MenuBarUI";
69
70     /*
71      * Model for the selected subcontrol.
72      */

73     private transient SingleSelectionModel JavaDoc selectionModel;
74
75     private boolean paintBorder = true;
76     private Insets JavaDoc margin = null;
77
78     /* diagnostic aids -- should be false for production builds. */
79     private static final boolean TRACE = false; // trace creates and disposes
80
private static final boolean VERBOSE = false; // show reuse hits/misses
81
private static final boolean DEBUG = false; // show bad params, misc.
82

83     /**
84      * Creates a new menu bar.
85      */

86     public JMenuBar() {
87         super();
88         setFocusTraversalKeysEnabled(false);
89         setSelectionModel(new DefaultSingleSelectionModel JavaDoc());
90         updateUI();
91     }
92
93     /**
94      * Returns the menubar's current UI.
95      * @see #setUI
96      */

97     public MenuBarUI getUI() {
98         return (MenuBarUI)ui;
99     }
100     
101     /**
102      * Sets the L&F object that renders this component.
103      *
104      * @param ui the new MenuBarUI L&F object
105      * @see UIDefaults#getUI
106      * @beaninfo
107      * bound: true
108      * hidden: true
109      * attribute: visualUpdate true
110      * description: The UI object that implements the Component's LookAndFeel.
111      */

112     public void setUI(MenuBarUI ui) {
113         super.setUI(ui);
114     }
115     
116     /**
117      * Resets the UI property with a value from the current look and feel.
118      *
119      * @see JComponent#updateUI
120      */

121     public void updateUI() {
122         setUI((MenuBarUI)UIManager.getUI(this));
123     }
124
125
126     /**
127      * Returns the name of the L&F class that renders this component.
128      *
129      * @return the string "MenuBarUI"
130      * @see JComponent#getUIClassID
131      * @see UIDefaults#getUI
132      */

133     public String JavaDoc getUIClassID() {
134         return uiClassID;
135     }
136
137
138     /**
139      * Returns the model object that handles single selections.
140      *
141      * @return the <code>SingleSelectionModel</code> property
142      * @see SingleSelectionModel
143      */

144     public SingleSelectionModel JavaDoc getSelectionModel() {
145         return selectionModel;
146     }
147
148     /**
149      * Sets the model object to handle single selections.
150      *
151      * @param model the <code>SingleSelectionModel</code> to use
152      * @see SingleSelectionModel
153      * @beaninfo
154      * bound: true
155      * description: The selection model, recording which child is selected.
156      */

157     public void setSelectionModel(SingleSelectionModel JavaDoc model) {
158     SingleSelectionModel JavaDoc oldValue = selectionModel;
159         this.selectionModel = model;
160         firePropertyChange("selectionModel", oldValue, selectionModel);
161     }
162
163
164     /**
165      * Appends the specified menu to the end of the menu bar.
166      *
167      * @param c the <code>JMenu</code> component to add
168      * @return the menu component
169      */

170     public JMenu JavaDoc add(JMenu JavaDoc c) {
171         super.add(c);
172         return c;
173     }
174
175     /**
176      * Returns the menu at the specified position in the menu bar.
177      *
178      * @param index an integer giving the position in the menu bar, where
179      * 0 is the first position
180      * @return the <code>JMenu</code> at that position, or <code>null</code> if
181      * if there is no <code>JMenu</code> at that position (ie. if
182      * it is a <code>JMenuItem</code>)
183      */

184     public JMenu JavaDoc getMenu(int index) {
185         Component JavaDoc c = getComponentAtIndex(index);
186         if (c instanceof JMenu JavaDoc)
187             return (JMenu JavaDoc) c;
188         return null;
189     }
190
191     /**
192      * Returns the number of items in the menu bar.
193      *
194      * @return the number of items in the menu bar
195      */

196     public int getMenuCount() {
197         return getComponentCount();
198     }
199
200     /**
201      * Sets the help menu that appears when the user selects the
202      * "help" option in the menu bar. This method is not yet implemented
203      * and will throw an exception.
204      *
205      * @param menu the JMenu that delivers help to the user
206      */

207     public void setHelpMenu(JMenu JavaDoc menu) {
208         throw new Error JavaDoc("setHelpMenu() not yet implemented.");
209     }
210
211     /**
212      * Gets the help menu for the menu bar. This method is not yet
213      * implemented and will throw an exception.
214      *
215      * @return the <code>JMenu</code> that delivers help to the user
216      */

217     public JMenu JavaDoc getHelpMenu() {
218         throw new Error JavaDoc("getHelpMenu() not yet implemented.");
219     }
220
221     /**
222      * Returns the component at the specified index.
223      *
224      * @param i an integer specifying the position, where 0 is first
225      * @return the <code>Component</code> at the position,
226      * or <code>null</code> for an invalid index
227      * @deprecated replaced by <code>getComponent(int i)</code>
228      */

229     @Deprecated JavaDoc
230     public Component JavaDoc getComponentAtIndex(int i) {
231     return getComponent(i);
232     }
233
234     /**
235      * Returns the index of the specified component.
236      *
237      * @param c the <code>Component</code> to find
238      * @return an integer giving the component's position, where 0 is first;
239      * or -1 if it can't be found
240      */

241     public int getComponentIndex(Component JavaDoc c) {
242         int ncomponents = this.getComponentCount();
243         Component JavaDoc[] component = this.getComponents();
244         for (int i = 0 ; i < ncomponents ; i++) {
245             Component JavaDoc comp = component[i];
246             if (comp == c)
247                 return i;
248         }
249         return -1;
250     }
251
252     /**
253      * Sets the currently selected component, producing a
254      * a change to the selection model.
255      *
256      * @param sel the <code>Component</code> to select
257      */

258     public void setSelected(Component JavaDoc sel) {
259         SingleSelectionModel JavaDoc model = getSelectionModel();
260         int index = getComponentIndex(sel);
261         model.setSelectedIndex(index);
262     }
263
264     /**
265      * Returns true if the menu bar currently has a component selected.
266      *
267      * @return true if a selection has been made, else false
268      */

269     public boolean isSelected() {
270         return selectionModel.isSelected();
271     }
272
273     /**
274      * Returns true if the menu bars border should be painted.
275      *
276      * @return true if the border should be painted, else false
277      */

278     public boolean isBorderPainted() {
279         return paintBorder;
280     }
281
282     /**
283      * Sets whether the border should be painted.
284      *
285      * @param b if true and border property is not <code>null</code>,
286      * the border is painted.
287      * @see #isBorderPainted
288      * @beaninfo
289      * bound: true
290      * attribute: visualUpdate true
291      * description: Whether the border should be painted.
292      */

293     public void setBorderPainted(boolean b) {
294         boolean oldValue = paintBorder;
295         paintBorder = b;
296         firePropertyChange("borderPainted", oldValue, paintBorder);
297         if (b != oldValue) {
298             revalidate();
299             repaint();
300         }
301     }
302
303     /**
304      * Paints the menubar's border if <code>BorderPainted</code>
305      * property is true.
306      *
307      * @param g the <code>Graphics</code> context to use for painting
308      * @see JComponent#paint
309      * @see JComponent#setBorder
310      */

311     protected void paintBorder(Graphics JavaDoc g) {
312         if (isBorderPainted()) {
313             super.paintBorder(g);
314         }
315     }
316
317     /**
318      * Sets the margin between the menubar's border and
319      * its menus. Setting to <code>null</code> will cause the menubar to
320      * use the default margins.
321      *
322      * @param m an Insets object containing the margin values
323      * @see Insets
324      * @beaninfo
325      * bound: true
326      * attribute: visualUpdate true
327      * description: The space between the menubar's border and its contents
328      */

329     public void setMargin(Insets JavaDoc m) {
330         Insets JavaDoc old = margin;
331         this.margin = m;
332         firePropertyChange("margin", old, m);
333         if (old == null || !old.equals(m)) {
334             revalidate();
335             repaint();
336         }
337     }
338
339     /**
340      * Returns the margin between the menubar's border and
341      * its menus. If there is no previous margin, it will create
342      * a default margin with zero size.
343      *
344      * @return an <code>Insets</code> object containing the margin values
345      * @see Insets
346      */

347     public Insets JavaDoc getMargin() {
348         if(margin == null) {
349             return new Insets JavaDoc(0,0,0,0);
350         } else {
351             return margin;
352         }
353     }
354
355
356     /**
357      * Implemented to be a <code>MenuElement</code> -- does nothing.
358      *
359      * @see #getSubElements
360      */

361     public void processMouseEvent(MouseEvent event,MenuElement JavaDoc path[],MenuSelectionManager JavaDoc manager) {
362     }
363
364     /**
365      * Implemented to be a <code>MenuElement</code> -- does nothing.
366      *
367      * @see #getSubElements
368      */

369     public void processKeyEvent(KeyEvent e,MenuElement JavaDoc path[],MenuSelectionManager JavaDoc manager) {
370     }
371
372     /**
373      * Implemented to be a <code>MenuElemen<code>t -- does nothing.
374      *
375      * @see #getSubElements
376      */

377     public void menuSelectionChanged(boolean isIncluded) {
378     }
379     
380     /**
381      * Implemented to be a <code>MenuElement</code> -- returns the
382      * menus in this menu bar.
383      * This is the reason for implementing the <code>MenuElement</code>
384      * interface -- so that the menu bar can be treated the same as
385      * other menu elements.
386      * @return an array of menu items in the menu bar.
387      */

388     public MenuElement JavaDoc[] getSubElements() {
389         MenuElement JavaDoc result[];
390         Vector JavaDoc tmp = new Vector JavaDoc();
391         int c = getComponentCount();
392         int i;
393         Component JavaDoc m;
394
395         for(i=0 ; i < c ; i++) {
396             m = getComponent(i);
397             if(m instanceof MenuElement JavaDoc)
398                 tmp.addElement(m);
399         }
400
401         result = new MenuElement JavaDoc[tmp.size()];
402         for(i=0,c=tmp.size() ; i < c ; i++)
403             result[i] = (MenuElement JavaDoc) tmp.elementAt(i);
404         return result;
405     }
406     
407     /**
408      * Implemented to be a <code>MenuElement</code>. Returns this object.
409      *
410      * @return the current <code>Component</code> (this)
411      * @see #getSubElements
412      */

413     public Component JavaDoc getComponent() {
414         return this;
415     }
416
417
418     /**
419      * Returns a string representation of this <code>JMenuBar</code>.
420      * This method
421      * is intended to be used only for debugging purposes, and the
422      * content and format of the returned string may vary between
423      * implementations. The returned string may be empty but may not
424      * be <code>null</code>.
425      *
426      * @return a string representation of this <code>JMenuBar</code>
427      */

428     protected String JavaDoc paramString() {
429     String JavaDoc paintBorderString = (paintBorder ?
430                     "true" : "false");
431     String JavaDoc marginString = (margin != null ?
432                    margin.toString() : "");
433
434     return super.paramString() +
435     ",margin=" + marginString +
436     ",paintBorder=" + paintBorderString;
437     }
438
439 /////////////////
440
// Accessibility support
441
////////////////
442

443     /**
444      * Gets the AccessibleContext associated with this JMenuBar.
445      * For JMenuBars, the AccessibleContext takes the form of an
446      * AccessibleJMenuBar.
447      * A new AccessibleJMenuBar instance is created if necessary.
448      *
449      * @return an AccessibleJMenuBar that serves as the
450      * AccessibleContext of this JMenuBar
451      */

452     public AccessibleContext getAccessibleContext() {
453         if (accessibleContext == null) {
454             accessibleContext = new AccessibleJMenuBar();
455         }
456         return accessibleContext;
457     }
458
459     /**
460      * This class implements accessibility support for the
461      * <code>JMenuBar</code> class. It provides an implementation of the
462      * Java Accessibility API appropriate to menu bar user-interface
463      * elements.
464      * <p>
465      * <strong>Warning:</strong>
466      * Serialized objects of this class will not be compatible with
467      * future Swing releases. The current serialization support is
468      * appropriate for short term storage or RMI between applications running
469      * the same version of Swing. As of 1.4, support for long term storage
470      * of all JavaBeans<sup><font size="-2">TM</font></sup>
471      * has been added to the <code>java.beans</code> package.
472      * Please see {@link java.beans.XMLEncoder}.
473      */

474     protected class AccessibleJMenuBar extends AccessibleJComponent
475         implements AccessibleSelection {
476
477         /**
478          * Get the accessible state set of this object.
479          *
480          * @return an instance of AccessibleState containing the current state
481          * of the object
482          */

483         public AccessibleStateSet getAccessibleStateSet() {
484             AccessibleStateSet states = super.getAccessibleStateSet();
485             return states;
486         }
487
488         /**
489          * Get the role of this object.
490          *
491          * @return an instance of AccessibleRole describing the role of the
492          * object
493          */

494         public AccessibleRole getAccessibleRole() {
495             return AccessibleRole.MENU_BAR;
496         }
497
498         /**
499          * Get the AccessibleSelection associated with this object. In the
500          * implementation of the Java Accessibility API for this class,
501      * return this object, which is responsible for implementing the
502          * AccessibleSelection interface on behalf of itself.
503      *
504      * @return this object
505          */

506         public AccessibleSelection getAccessibleSelection() {
507             return this;
508         }
509
510         /**
511          * Returns 1 if a menu is currently selected in this menu bar.
512          *
513          * @return 1 if a menu is currently selected, else 0
514          */

515          public int getAccessibleSelectionCount() {
516             if (isSelected()) {
517                 return 1;
518             } else {
519                 return 0;
520             }
521          }
522     
523         /**
524          * Returns the currently selected menu if one is selected,
525          * otherwise null.
526          */

527          public Accessible getAccessibleSelection(int i) {
528             if (isSelected()) {
529         if (i != 0) { // single selection model for JMenuBar
530
return null;
531         }
532                 int j = getSelectionModel().getSelectedIndex();
533                 if (getComponentAtIndex(j) instanceof Accessible) {
534                     return (Accessible) getComponentAtIndex(j);
535                 }
536             }
537             return null;
538          }
539
540         /**
541          * Returns true if the current child of this object is selected.
542          *
543          * @param i the zero-based index of the child in this Accessible
544          * object.
545          * @see AccessibleContext#getAccessibleChild
546          */

547         public boolean isAccessibleChildSelected(int i) {
548             return (i == getSelectionModel().getSelectedIndex());
549         }
550
551         /**
552          * Selects the nth menu in the menu bar, forcing it to
553      * pop up. If another menu is popped up, this will force
554      * it to close. If the nth menu is already selected, this
555      * method has no effect.
556          *
557          * @param i the zero-based index of selectable items
558          * @see #getAccessibleStateSet
559          */

560         public void addAccessibleSelection(int i) {
561         // first close up any open menu
562
int j = getSelectionModel().getSelectedIndex();
563         if (i == j) {
564         return;
565         }
566         if (j >= 0 && j < getMenuCount()) {
567                 JMenu JavaDoc menu = getMenu(j);
568                 if (menu != null) {
569             MenuSelectionManager.defaultManager().setSelectedPath(null);
570 // menu.setPopupMenuVisible(false);
571
}
572         }
573         // now popup the new menu
574
getSelectionModel().setSelectedIndex(i);
575         JMenu JavaDoc menu = getMenu(i);
576         if (menu != null) {
577         MenuElement JavaDoc me[] = new MenuElement JavaDoc[3];
578         me[0] = JMenuBar.this;
579         me[1] = menu;
580         me[2] = menu.getPopupMenu();
581         MenuSelectionManager.defaultManager().setSelectedPath(me);
582 // menu.setPopupMenuVisible(true);
583
}
584         }
585     
586         /**
587          * Removes the nth selected item in the object from the object's
588          * selection. If the nth item isn't currently selected, this
589          * method has no effect. Otherwise, it closes the popup menu.
590          *
591          * @param i the zero-based index of selectable items
592          */

593         public void removeAccessibleSelection(int i) {
594         if (i >= 0 && i < getMenuCount()) {
595         JMenu JavaDoc menu = getMenu(i);
596         if (menu != null) {
597             MenuSelectionManager.defaultManager().setSelectedPath(null);
598 // menu.setPopupMenuVisible(false);
599
}
600         getSelectionModel().setSelectedIndex(-1);
601         }
602         }
603     
604         /**
605          * Clears the selection in the object, so that nothing in the
606          * object is selected. This will close any open menu.
607          */

608         public void clearAccessibleSelection() {
609         int i = getSelectionModel().getSelectedIndex();
610         if (i >= 0 && i < getMenuCount()) {
611         JMenu JavaDoc menu = getMenu(i);
612         if (menu != null) {
613             MenuSelectionManager.defaultManager().setSelectedPath(null);
614 // menu.setPopupMenuVisible(false);
615
}
616         }
617             getSelectionModel().setSelectedIndex(-1);
618         }
619
620         /**
621          * Normally causes every selected item in the object to be selected
622          * if the object supports multiple selections. This method
623      * makes no sense in a menu bar, and so does nothing.
624          */

625         public void selectAllAccessibleSelection() {
626         }
627     } // internal class AccessibleJMenuBar
628

629
630     /**
631      * Subclassed to check all the child menus.
632      */

633     protected boolean processKeyBinding(KeyStroke JavaDoc ks, KeyEvent e,
634                     int condition, boolean pressed) {
635     // See if we have a local binding.
636
boolean retValue = super.processKeyBinding(ks, e, condition, pressed);
637     if (!retValue) {
638             MenuElement JavaDoc[] subElements = getSubElements();
639             for (int i=0; i<subElements.length; i++) {
640                 if (processBindingForKeyStrokeRecursive(
641                                                         subElements[i], ks, e, condition, pressed)) {
642                     return true;
643                 }
644             }
645         }
646         return retValue;
647     }
648
649     static boolean processBindingForKeyStrokeRecursive(MenuElement JavaDoc elem,
650                                                        KeyStroke JavaDoc ks, KeyEvent e, int condition, boolean pressed) {
651         if (elem == null) {
652             return false;
653         }
654
655         Component JavaDoc c = elem.getComponent();
656         if (c != null && c instanceof JComponent JavaDoc &&
657             ((JComponent JavaDoc)c).processKeyBinding(ks, e, condition, pressed)) {
658
659             return true;
660         }
661
662         MenuElement JavaDoc[] subElements = elem.getSubElements();
663         for(int i=0; i<subElements.length; i++) {
664             if (processBindingForKeyStrokeRecursive(subElements[i], ks, e,
665                                                     condition, pressed)) {
666                 return true;
667                 // We don't, pass along to children JMenu's
668
}
669         }
670         return false;
671     }
672
673     /**
674      * Overrides <code>JComponent.addNotify</code> to register this
675      * menu bar with the current keyboard manager.
676      */

677     public void addNotify() {
678         super.addNotify();
679     KeyboardManager.getCurrentManager().registerMenuBar(this);
680     }
681
682     /**
683      * Overrides <code>JComponent.removeNotify</code> to unregister this
684      * menu bar with the current keyboard manager.
685      */

686     public void removeNotify() {
687         super.removeNotify();
688     KeyboardManager.getCurrentManager().unregisterMenuBar(this);
689     }
690
691
692     private void writeObject(ObjectOutputStream JavaDoc s) throws IOException JavaDoc {
693         s.defaultWriteObject();
694         if (getUIClassID().equals(uiClassID)) {
695             byte count = JComponent.getWriteObjCounter(this);
696             JComponent.setWriteObjCounter(this, --count);
697             if (count == 0 && ui != null) {
698                 ui.installUI(this);
699             }
700         }
701
702         Object JavaDoc[] kvData = new Object JavaDoc[4];
703         int n = 0;
704
705         if (selectionModel instanceof Serializable JavaDoc) {
706             kvData[n++] = "selectionModel";
707             kvData[n++] = selectionModel;
708         }
709
710         s.writeObject(kvData);
711     }
712
713
714     /**
715      * See JComponent.readObject() for information about serialization
716      * in Swing.
717      */

718     private void readObject(ObjectInputStream JavaDoc s) throws IOException JavaDoc, ClassNotFoundException JavaDoc
719     {
720         s.defaultReadObject();
721         Object JavaDoc[] kvData = (Object JavaDoc[])(s.readObject());
722
723         for(int i = 0; i < kvData.length; i += 2) {
724             if (kvData[i] == null) {
725                 break;
726             }
727             else if (kvData[i].equals("selectionModel")) {
728                 selectionModel = (SingleSelectionModel JavaDoc)kvData[i + 1];
729             }
730         }
731
732     }
733 }
734
735
Popular Tags