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