1. /*
  2. * @(#)BasicPopupMenuUI.java 1.67 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.plaf.basic;
  8. import javax.swing.*;
  9. import javax.swing.event.*;
  10. import javax.swing.plaf.*;
  11. import javax.swing.border.*;
  12. import java.awt.Color;
  13. import java.awt.Component;
  14. import java.awt.Container;
  15. import java.awt.Dimension;
  16. import java.awt.Frame;
  17. import java.awt.Graphics;
  18. import java.awt.Insets;
  19. import java.awt.Point;
  20. import java.awt.Rectangle;
  21. import java.awt.Window;
  22. import java.awt.event.*;
  23. import java.util.*;
  24. /**
  25. * A Windows L&F implementation of PopupMenuUI. This implementation
  26. * is a "combined" view/controller.
  27. *
  28. * @version 1.67 11/29/01
  29. * @author Georges Saab
  30. * @author David Karlton
  31. * @author Arnaud Weber
  32. */
  33. public class BasicPopupMenuUI extends PopupMenuUI {
  34. protected JPopupMenu popupMenu = null;
  35. private Frame frame;
  36. public static ComponentUI createUI(JComponent x) {
  37. return new BasicPopupMenuUI();
  38. }
  39. public void installUI(JComponent c) {
  40. popupMenu = (JPopupMenu) c;
  41. installDefaults();
  42. installListeners();
  43. installKeyboardActions();
  44. }
  45. public void installDefaults() {
  46. if (popupMenu.getLayout() == null ||
  47. popupMenu.getLayout() instanceof UIResource)
  48. popupMenu.setLayout(new DefaultMenuLayout(popupMenu, BoxLayout.Y_AXIS));
  49. popupMenu.setOpaque(true);
  50. LookAndFeel.installBorder(popupMenu, "PopupMenu.border");
  51. LookAndFeel.installColorsAndFont(popupMenu,
  52. "PopupMenu.background",
  53. "PopupMenu.foreground",
  54. "PopupMenu.font");
  55. }
  56. protected void installListeners() {
  57. if (mouseGrabber == null)
  58. mouseGrabber = new MouseGrabber();
  59. }
  60. protected void installKeyboardActions() {}
  61. public void uninstallUI(JComponent c) {
  62. uninstallDefaults();
  63. uninstallListeners();
  64. uninstallKeyboardActions();
  65. popupMenu = null;
  66. }
  67. protected void uninstallDefaults() {
  68. LookAndFeel.uninstallBorder(popupMenu);
  69. }
  70. protected void uninstallListeners() {
  71. }
  72. protected void uninstallKeyboardActions() {}
  73. public Dimension getMinimumSize(JComponent c) {
  74. return getPreferredSize(c);
  75. }
  76. public Dimension getPreferredSize(JComponent c) {
  77. return null;
  78. }
  79. public Dimension getMaximumSize(JComponent c) {
  80. return getPreferredSize(c);
  81. }
  82. ///////////////////////////////////////////////////////////////////////////////
  83. //// Grab Code
  84. ///////////////////////////////////////////////////////////////////////////////
  85. private static Window getWindow(Component c) {
  86. Component w = c;
  87. while(!(w instanceof Window) && (w!=null)) {
  88. w = w.getParent();
  89. }
  90. return (Window)w;
  91. }
  92. private transient static MouseGrabber mouseGrabber = null;
  93. private static class MouseGrabber implements MouseListener, MouseMotionListener,WindowListener,ComponentListener, ChangeListener {
  94. Vector grabbed = new Vector();
  95. MenuElement lastGrabbed = null;
  96. boolean lastGrabbedMenuBarChild = false;
  97. public MouseGrabber() {
  98. MenuSelectionManager msm = MenuSelectionManager.defaultManager();
  99. msm.addChangeListener(this);
  100. }
  101. private void requestAddGrab(Component invoker) {
  102. Window ancestor;
  103. ancestor = getWindow(invoker);
  104. MenuSelectionManager msm = MenuSelectionManager.defaultManager();
  105. MenuElement[] p = msm.getSelectedPath();
  106. Component excluded = null;
  107. for(int i = 0 ; excluded == null && i < p.length ; i++) {
  108. if (p[i] instanceof JPopupMenu)
  109. excluded = p[i].getComponent();
  110. }
  111. grabContainer(ancestor, excluded);
  112. }
  113. private void requestRemoveGrab() {
  114. ungrabContainers();
  115. }
  116. void cancelPopupMenu() {
  117. MenuSelectionManager msm = MenuSelectionManager.defaultManager();
  118. MenuElement[] p = msm.getSelectedPath();
  119. if (lastGrabbed==getFirstPopup()) {
  120. MenuSelectionManager.defaultManager().clearSelectedPath();
  121. ungrabContainers();
  122. } else {
  123. // The cancel has cause another menu selection
  124. lastGrabbed=getFirstPopup();
  125. if (p[0] instanceof JMenuBar) {
  126. lastGrabbedMenuBarChild = true;
  127. } else {
  128. lastGrabbedMenuBarChild = false;
  129. }
  130. }
  131. }
  132. MenuElement[] lastPathSelected = new MenuElement[0];
  133. public void stateChanged(ChangeEvent e) {
  134. MenuSelectionManager msm = MenuSelectionManager.defaultManager();
  135. MenuElement[] p = msm.getSelectedPath();
  136. if (lastPathSelected.length == 0 &&
  137. p.length != 0) {
  138. // A grab needs to be added
  139. Component invoker = p[0].getComponent();
  140. if (invoker instanceof JPopupMenu)
  141. invoker = ((JPopupMenu)invoker).getInvoker();
  142. requestAddGrab(invoker);
  143. }
  144. if (lastPathSelected.length != 0 &&
  145. p.length == 0) {
  146. // The grab should be removed
  147. requestRemoveGrab();
  148. }
  149. // Switch between menubar children
  150. if (p!=null && p.length>2 && (p[0] instanceof JMenuBar &&
  151. lastGrabbedMenuBarChild == true)) {
  152. if (!(lastGrabbed==getFirstPopup())) {
  153. lastGrabbed=getFirstPopup();
  154. if (p[0] instanceof JMenuBar) {
  155. lastGrabbedMenuBarChild = true;
  156. } else {
  157. lastGrabbedMenuBarChild = false;
  158. }
  159. }
  160. }
  161. // Remember the last path selected
  162. lastPathSelected = p;
  163. }
  164. private MenuElement getFirstPopup() {
  165. MenuSelectionManager msm = MenuSelectionManager.defaultManager();
  166. MenuElement[] p = msm.getSelectedPath();
  167. MenuElement me = null;
  168. for(int i = 0 ; me == null && i < p.length ; i++) {
  169. if (p[i] instanceof JPopupMenu)
  170. me = p[i];
  171. }
  172. return me;
  173. }
  174. void grabContainer(Container c, Component excluded) {
  175. if(c == excluded)
  176. return;
  177. MenuSelectionManager msm = MenuSelectionManager.defaultManager();
  178. MenuElement[] p = msm.getSelectedPath();
  179. lastGrabbed = getFirstPopup();
  180. if (p[0] instanceof JMenuBar) {
  181. lastGrabbedMenuBarChild = true;
  182. } else {
  183. lastGrabbedMenuBarChild = false;
  184. }
  185. if(c instanceof java.awt.Window) {
  186. ((java.awt.Window)c).addWindowListener(this);
  187. ((java.awt.Window)c).addComponentListener(this);
  188. grabbed.addElement(c);
  189. }
  190. synchronized(c.getTreeLock()) {
  191. int ncomponents = c.getComponentCount();
  192. Component[] component = c.getComponents();
  193. for (int i = 0 ; i < ncomponents ; i++) {
  194. Component comp = component[i];
  195. if(!comp.isVisible())
  196. continue;
  197. comp.addMouseListener(this);
  198. comp.addMouseMotionListener(this);
  199. grabbed.addElement(comp);
  200. if (comp instanceof Container) {
  201. Container cont = (Container) comp;
  202. grabContainer(cont, excluded);
  203. }
  204. }
  205. }
  206. }
  207. void ungrabContainers() {
  208. int i,c;
  209. Component cpn;
  210. for(i=0,c=grabbed.size();i<c;i++) {
  211. cpn = (Component)grabbed.elementAt(i);
  212. if(cpn instanceof java.awt.Window) {
  213. ((java.awt.Window)cpn).removeWindowListener(this);
  214. ((java.awt.Window)cpn).removeComponentListener(this);
  215. } else {
  216. cpn.removeMouseListener(this);
  217. cpn.removeMouseMotionListener(this);
  218. }
  219. }
  220. grabbed = new Vector();
  221. lastGrabbed = null;
  222. lastGrabbedMenuBarChild = false;
  223. }
  224. public void mousePressed(MouseEvent e) {
  225. Component c = (Component)e.getSource();
  226. MenuSelectionManager msm = MenuSelectionManager.defaultManager();
  227. cancelPopupMenu();
  228. /*
  229. if(msm.isComponentPartOfCurrentMenu(popupMenu) && msm.isComponentPartOfCurrentMenu(c)) {
  230. return;
  231. } else {
  232. cancelPopupMenu();
  233. }
  234. */
  235. }
  236. public void mouseReleased(MouseEvent e) {
  237. MenuSelectionManager.defaultManager().processMouseEvent(e);
  238. }
  239. public void mouseEntered(MouseEvent e) {
  240. // MenuSelectionManager.defaultManager().processMouseEvent(e);
  241. }
  242. public void mouseExited(MouseEvent e) {
  243. // MenuSelectionManager.defaultManager().processMouseEvent(e);
  244. }
  245. public void mouseMoved(MouseEvent e) {
  246. // MenuSelectionManager.defaultManager().processMouseEvent(e);
  247. }
  248. public void mouseDragged(MouseEvent e) {
  249. MenuSelectionManager.defaultManager().processMouseEvent(e);
  250. }
  251. public void mouseClicked(MouseEvent e) {
  252. }
  253. public void componentResized(ComponentEvent e) {
  254. cancelPopupMenu();
  255. }
  256. public void componentMoved(ComponentEvent e) {
  257. cancelPopupMenu();
  258. }
  259. public void componentShown(ComponentEvent e) {
  260. cancelPopupMenu();
  261. }
  262. public void componentHidden(ComponentEvent e) {
  263. cancelPopupMenu();
  264. }
  265. public void windowOpened(WindowEvent e) {}
  266. public void windowClosing(WindowEvent e) {
  267. cancelPopupMenu();
  268. }
  269. public void windowClosed(WindowEvent e) {
  270. cancelPopupMenu();
  271. }
  272. public void windowIconified(WindowEvent e) {
  273. cancelPopupMenu();
  274. }
  275. public void windowDeiconified(WindowEvent e) {}
  276. public void windowActivated(WindowEvent e) {
  277. /* cancelPopupMenu(); cannot do this because
  278. this might happen when using cascading heavy weight
  279. menus
  280. */
  281. }
  282. public void windowDeactivated(WindowEvent e) {
  283. /* cancelPopupMenu(); cannot do this because
  284. this might happen when using cascading heavy weight
  285. menus
  286. */
  287. }
  288. }
  289. }