OSDN Git Service

f8936be5b66544f30a8cb79272117775a6236e3b
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / swing / plaf / basic / BasicMenuUI.java
1 /* BasicMenuUI.java
2    Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package javax.swing.plaf.basic;
40
41 import gnu.classpath.NotImplementedException;
42
43 import java.awt.Component;
44 import java.awt.Dimension;
45 import java.awt.event.MouseEvent;
46 import java.beans.PropertyChangeListener;
47
48 import javax.swing.JComponent;
49 import javax.swing.JMenu;
50 import javax.swing.JMenuBar;
51 import javax.swing.JPopupMenu;
52 import javax.swing.LookAndFeel;
53 import javax.swing.MenuSelectionManager;
54 import javax.swing.UIDefaults;
55 import javax.swing.UIManager;
56 import javax.swing.event.ChangeEvent;
57 import javax.swing.event.ChangeListener;
58 import javax.swing.event.MenuDragMouseEvent;
59 import javax.swing.event.MenuDragMouseListener;
60 import javax.swing.event.MenuEvent;
61 import javax.swing.event.MenuKeyEvent;
62 import javax.swing.event.MenuKeyListener;
63 import javax.swing.event.MenuListener;
64 import javax.swing.event.MouseInputListener;
65 import javax.swing.plaf.ComponentUI;
66
67 /**
68  * UI Delegate for JMenu
69  */
70 public class BasicMenuUI extends BasicMenuItemUI
71 {
72   protected ChangeListener changeListener;
73
74   /* MenuListener listens to MenuEvents fired by JMenu */
75   protected MenuListener menuListener;
76
77   /* PropertyChangeListner that listens to propertyChangeEvents occuring in JMenu*/
78   protected PropertyChangeListener propertyChangeListener;
79
80   /**
81    * Creates a new BasicMenuUI object.
82    */
83   public BasicMenuUI()
84   {
85     mouseInputListener = createMouseInputListener((JMenu) menuItem);
86     menuListener = createMenuListener((JMenu) menuItem);
87     propertyChangeListener = createPropertyChangeListener((JMenu) menuItem);
88   }
89
90   /**
91    * This method creates a new ChangeListener.
92    *
93    * @return A new ChangeListener.
94    */
95   protected ChangeListener createChangeListener(JComponent c)
96   {
97     return new ChangeHandler((JMenu) c, this);
98   }
99
100   /**
101    * This method creates new MenuDragMouseListener to listen to mouse dragged events
102    * occuring in the Menu
103    *
104    * @param c the menu to listen to
105    *
106    * @return The MenuDrageMouseListener
107    */
108   protected MenuDragMouseListener createMenuDragMouseListener(JComponent c)
109   {
110     return new MenuDragMouseHandler();
111   }
112
113   /**
114    * This method creates new MenuDragKeyListener to listen to key events
115    *
116    * @param c the menu to listen to
117    *
118    * @return The MenuKeyListener
119    */
120   protected MenuKeyListener createMenuKeyListener(JComponent c)
121   {
122     return new MenuKeyHandler();
123   }
124
125   /**
126    * This method creates new MenuListener to listen to menu events
127    * occuring in the Menu
128    *
129    * @param c the menu to listen to
130    *
131    * @return The MenuListener
132    */
133   protected MenuListener createMenuListener(JComponent c)
134   {
135     return new MenuHandler();
136   }
137
138   /**
139    * This method creates new MouseInputListener to listen to mouse input events
140    * occuring in the Menu
141    *
142    * @param c the menu to listen to
143    *
144    * @return The MouseInputListener
145    */
146   protected MouseInputListener createMouseInputListener(JComponent c)
147   {
148     return new MouseInputHandler();
149   }
150
151   /**
152    * This method creates newPropertyChangeListener to listen to property changes
153    * occuring in the Menu
154    *
155    * @param c the menu to listen to
156    *
157    * @return The PropertyChangeListener
158    */
159   protected PropertyChangeListener createPropertyChangeListener(JComponent c)
160   {
161     return new PropertyChangeHandler();
162   }
163
164   /**
165    * This method creates a new BasicMenuUI.
166    *
167    * @param c The JComponent to create a UI for.
168    *
169    * @return A new BasicMenuUI.
170    */
171   public static ComponentUI createUI(JComponent c)
172   {
173     return new BasicMenuUI();
174   }
175
176   /**
177    * Get the component's maximum size.
178    *
179    * @param c The JComponent for which to get maximum size
180    *
181    * @return The maximum size of the component
182    */
183   public Dimension getMaximumSize(JComponent c)
184   {
185     return c.getPreferredSize();
186   }
187
188   /**
189    * Returns the prefix for entries in the {@link UIDefaults} table.
190    *
191    * @return "Menu"
192    */
193   protected String getPropertyPrefix()
194   {
195     return "Menu";
196   }
197
198   /**
199    * Initializes any default properties that this UI has from the defaults for
200    * the Basic look and feel.
201    */
202   protected void installDefaults()
203   {
204     LookAndFeel.installBorder(menuItem, "Menu.border");
205     LookAndFeel.installColorsAndFont(menuItem, "Menu.background",
206                                      "Menu.foreground", "Menu.font");
207     menuItem.setMargin(UIManager.getInsets("Menu.margin"));
208     acceleratorFont = UIManager.getFont("Menu.acceleratorFont");
209     acceleratorForeground = UIManager.getColor("Menu.acceleratorForeground");
210     acceleratorSelectionForeground = UIManager.getColor("Menu.acceleratorSelectionForeground");
211     selectionBackground = UIManager.getColor("Menu.selectionBackground");
212     selectionForeground = UIManager.getColor("Menu.selectionForeground");
213     arrowIcon = UIManager.getIcon("Menu.arrowIcon");
214     oldBorderPainted = UIManager.getBoolean("Menu.borderPainted");
215   }
216
217   /**
218    * Installs any keyboard actions. The list of keys that need to be bound are
219    * listed in Basic look and feel's defaults.
220    *
221    */
222   protected void installKeyboardActions()
223     throws NotImplementedException
224   {
225     // FIXME: Need to implement
226   }
227
228   /**
229    * Creates and registers all the listeners for this UI delegate.
230    */
231   protected void installListeners()
232   {
233     ((JMenu) menuItem).addMouseListener(mouseInputListener);
234     ((JMenu) menuItem).addMouseMotionListener(mouseInputListener);
235     ((JMenu) menuItem).addMenuListener(menuListener);
236     ((JMenu) menuItem).addMenuDragMouseListener(menuDragMouseListener);
237   }
238
239   protected void setupPostTimer(JMenu menu)
240   {
241     // TODO: Implement this properly.
242   }
243
244   /**
245    * This method uninstalls the defaults and sets any objects created during
246    * install to null
247    */
248   protected void uninstallDefaults()
249   {
250     menuItem.setBackground(null);
251     menuItem.setBorder(null);
252     menuItem.setFont(null);
253     menuItem.setForeground(null);
254     menuItem.setMargin(null);
255     acceleratorFont = null;
256     acceleratorForeground = null;
257     acceleratorSelectionForeground = null;
258     selectionBackground = null;
259     selectionForeground = null;
260     arrowIcon = null;
261   }
262
263   /**
264    * Uninstalls any keyboard actions. The list of keys used  are listed in
265    * Basic look and feel's defaults.
266    */
267   protected void uninstallKeyboardActions()
268     throws NotImplementedException
269   {
270     // FIXME: Need to implement
271   }
272
273   /**
274    * Unregisters all the listeners that this UI delegate was using. In
275    * addition, it will also null any listeners that it was using.
276    */
277   protected void uninstallListeners()
278   {
279     ((JMenu) menuItem).removeMouseListener(mouseInputListener);
280     ((JMenu) menuItem).removeMenuListener(menuListener);
281     ((JMenu) menuItem).removePropertyChangeListener(propertyChangeListener);
282   }
283
284   /**
285    * This class is used by menus to handle mouse events occuring in the
286    * menu.
287    */
288   protected class MouseInputHandler implements MouseInputListener
289   {
290     public void mouseClicked(MouseEvent e)
291     {
292       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
293       manager.processMouseEvent(e);
294     }
295
296     public void mouseDragged(MouseEvent e)
297     {
298       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
299       manager.processMouseEvent(e);
300     }
301
302     private boolean popupVisible()
303     {
304       JMenuBar mb = (JMenuBar) ((JMenu) menuItem).getParent();
305       // check if mb.isSelected because if no menus are selected
306       // we don't have to look through the list for popup menus
307       if (!mb.isSelected())
308         return false;
309       for (int i = 0; i < mb.getMenuCount(); i++)
310       {
311          JMenu m = mb.getMenu(i);
312         if (m != null && m.isPopupMenuVisible())
313           return true;
314       }
315       return false;
316     }
317
318     public void mouseEntered(MouseEvent e)
319     {
320       /* When mouse enters menu item, it should be considered selected
321
322        if (i) if this menu is a submenu in some other menu
323           (ii) or if this menu is in a menu bar and some other menu in a 
324           menu bar was just selected and has its popup menu visible. 
325                (If nothing was selected, menu should be pressed before
326                it will be selected)
327       */
328       JMenu menu = (JMenu) menuItem;
329
330       // NOTE: the following if used to require !menu.isArmed but I could find
331       // no reason for this and it was preventing some JDK-compatible behaviour.
332       // Specifically, if a menu is selected but its popup menu not visible,
333       // and then another menu is selected whose popup menu IS visible, when
334       // the mouse is moved over the first menu, its popup menu should become
335       // visible.
336
337       if (! menu.isTopLevelMenu() || popupVisible())
338         {
339           // set new selection and forward this event to MenuSelectionManager
340           MenuSelectionManager manager = MenuSelectionManager.defaultManager();
341           manager.setSelectedPath(getPath());
342           manager.processMouseEvent(e);
343         }
344     }
345
346     public void mouseExited(MouseEvent e)
347     {
348       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
349       manager.processMouseEvent(e);
350     }
351
352     public void mouseMoved(MouseEvent e)
353     {
354       // TODO: What should be done here, if anything?
355     }
356
357     public void mousePressed(MouseEvent e)
358     {
359       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
360       JMenu menu = (JMenu) menuItem;
361       manager.processMouseEvent(e);
362
363       // Menu should be displayed when the menu is pressed only if 
364       // it is top-level menu
365       if (menu.isTopLevelMenu())
366         {
367           if (menu.getPopupMenu().isVisible())
368             // If menu is visible and menu button was pressed.. 
369             // then need to cancel the menu
370             manager.clearSelectedPath();
371           else
372             {
373               // Display the menu
374               int x = 0;
375               int y = menu.getHeight();
376
377               manager.setSelectedPath(getPath());
378
379               JMenuBar mb = (JMenuBar) menu.getParent();
380
381               // set selectedIndex of the selectionModel of a menuBar
382               mb.getSelectionModel().setSelectedIndex(mb.getComponentIndex(menu));
383             }
384         }
385     }
386
387     public void mouseReleased(MouseEvent e)
388     {
389       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
390       manager.processMouseEvent(e);
391     }
392   }
393
394   /**
395    * This class handles MenuEvents fired by the JMenu
396    */
397   private class MenuHandler implements MenuListener
398   {
399     /**
400      * This method is called when menu is cancelled. The menu is cancelled
401      * when its popup menu is closed without selection. It clears selected index
402      * in the selectionModel of the menu parent.
403      *
404      * @param e The MenuEvent.
405      */
406     public void menuCanceled(MenuEvent e)
407     {
408       menuDeselected(e);
409     }
410
411     /**
412      * This method is called when menu is deselected. It clears selected index
413      * in the selectionModel of the menu parent.
414      *
415      * @param e The MenuEvent.
416      */
417     public void menuDeselected(MenuEvent e)
418     {
419       JMenu menu = (JMenu) menuItem;
420       if (menu.getParent() != null)
421         {
422           if (menu.isTopLevelMenu())
423             ((JMenuBar) menu.getParent()).getSelectionModel().clearSelection();
424           else
425             ((JPopupMenu) menu.getParent()).getSelectionModel().clearSelection();
426         }
427     }
428
429     /**
430      * This method is called when menu is selected.  It sets selected index
431      * in the selectionModel of the menu parent.
432      *
433      * @param e The MenuEvent.
434      */
435     public void menuSelected(MenuEvent e)
436     {
437       JMenu menu = (JMenu) menuItem;
438       if (menu.isTopLevelMenu())
439         ((JMenuBar) menu.getParent()).setSelected(menu);
440       else
441         ((JPopupMenu) menu.getParent()).setSelected(menu);
442     }
443   }
444
445   /**
446    * Obsolete as of JDK1.4.
447    */
448   public class ChangeHandler implements ChangeListener
449   {
450     /**
451      * Not used.
452      */
453     public boolean isSelected;
454
455     /**
456      * Not used.
457      */
458     public JMenu menu;
459
460     /**
461      * Not used.
462      */
463     public BasicMenuUI ui;
464
465     /**
466      * Not used.
467      */
468     public Component wasFocused;
469
470     /**
471      * Not used.
472      */
473     public ChangeHandler(JMenu m, BasicMenuUI ui)
474     {
475       // Not used.
476     }
477
478     /**
479      * Not used.
480      */
481     public void stateChanged(ChangeEvent e)
482     {
483       // Not used.
484     }
485   }
486
487   /**
488    * This class handles mouse dragged events occuring in the menu.
489    */
490   private class MenuDragMouseHandler implements MenuDragMouseListener
491   {
492     /**
493      * This method is invoked when mouse is dragged over the menu item.
494      *
495      * @param e The MenuDragMouseEvent
496      */
497     public void menuDragMouseDragged(MenuDragMouseEvent e)
498     {
499       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
500       manager.setSelectedPath(e.getPath());
501     }
502
503     /**
504      * This method is invoked when mouse enters the menu item while it is
505      * being dragged.
506      *
507      * @param e The MenuDragMouseEvent
508      */
509     public void menuDragMouseEntered(MenuDragMouseEvent e)
510     {
511       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
512       manager.setSelectedPath(e.getPath());
513     }
514
515     /**
516      * This method is invoked when mouse exits the menu item while
517      * it is being dragged
518      *
519      * @param e The MenuDragMouseEvent
520      */
521     public void menuDragMouseExited(MenuDragMouseEvent e)
522     {
523       // TODO: What should be done here, if anything?
524     }
525
526     /**
527      * This method is invoked when mouse was dragged and released
528      * inside the menu item.
529      *
530      * @param e The MenuDragMouseEvent
531      */
532     public void menuDragMouseReleased(MenuDragMouseEvent e)
533     {
534       // TODO: What should be done here, if anything?
535     }
536   }
537
538   /**
539    * This class handles key events occuring when menu item is visible on the
540    * screen.
541    */
542   private class MenuKeyHandler implements MenuKeyListener
543   {
544     /**
545      * This method is invoked when key has been pressed
546      *
547      * @param e A {@link MenuKeyEvent}.
548      */
549     public void menuKeyPressed(MenuKeyEvent e)
550     {
551       // TODO: What should be done here, if anything?
552     }
553
554     /**
555      * This method is invoked when key has been pressed
556      *
557      * @param e A {@link MenuKeyEvent}.
558      */
559     public void menuKeyReleased(MenuKeyEvent e)
560     {
561       // TODO: What should be done here, if anything?
562     }
563
564     /**
565      * This method is invoked when key has been typed
566      * It handles the mnemonic key for the menu item.
567      *
568      * @param e A {@link MenuKeyEvent}.
569      */
570     public void menuKeyTyped(MenuKeyEvent e)
571     {
572       // TODO: What should be done here, if anything?
573     }
574   }
575 }