1. /*
  2. * @(#)BasicMenuUI.java 1.131 01/02/09
  3. *
  4. * Copyright 1997-2001 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 java.awt.*;
  12. import java.awt.event.*;
  13. import java.beans.*;
  14. import javax.swing.*;
  15. import javax.swing.event.*;
  16. import javax.swing.plaf.*;
  17. import javax.swing.border.*;
  18. /**
  19. * A default L&F implementation of MenuUI. This implementation
  20. * is a "combined" view/controller.
  21. *
  22. * @version 1.131 02/09/01
  23. * @author Georges Saab
  24. * @author David Karlton
  25. * @author Arnaud Weber
  26. */
  27. public class BasicMenuUI extends BasicMenuItemUI
  28. {
  29. protected ChangeListener changeListener;
  30. protected PropertyChangeListener propertyChangeListener;
  31. protected MenuListener menuListener;
  32. private int lastMnemonic = 0;
  33. /** Uses as the parent of the windowInputMap when selected. */
  34. private InputMap selectedWindowInputMap;
  35. /* diagnostic aids -- should be false for production builds. */
  36. private static final boolean TRACE = false; // trace creates and disposes
  37. private static final boolean VERBOSE = false; // show reuse hits/misses
  38. private static final boolean DEBUG = false; // show bad params, misc.
  39. public static ComponentUI createUI(JComponent x) {
  40. return new BasicMenuUI();
  41. }
  42. protected void installDefaults() {
  43. super.installDefaults();
  44. ((JMenu)menuItem).setDelay(200);
  45. }
  46. protected String getPropertyPrefix() {
  47. return "Menu";
  48. }
  49. protected void installListeners() {
  50. super.installListeners();
  51. changeListener = createChangeListener(menuItem);
  52. propertyChangeListener = createPropertyChangeListener(menuItem);
  53. menuListener = createMenuListener(menuItem);
  54. menuItem.addChangeListener(changeListener);
  55. menuItem.addPropertyChangeListener(propertyChangeListener);
  56. ((JMenu)menuItem).addMenuListener(menuListener);
  57. }
  58. protected void installKeyboardActions() {
  59. super.installKeyboardActions();
  60. updateMnemonicBinding();
  61. }
  62. void updateMnemonicBinding() {
  63. int mnemonic = menuItem.getModel().getMnemonic();
  64. if (mnemonic == lastMnemonic) {
  65. return;
  66. }
  67. if (lastMnemonic != 0 && windowInputMap != null) {
  68. windowInputMap.remove(KeyStroke.getKeyStroke
  69. (lastMnemonic, ActionEvent.ALT_MASK, false));
  70. }
  71. if (mnemonic != 0) {
  72. if (windowInputMap == null) {
  73. windowInputMap = createInputMap(JComponent.
  74. WHEN_IN_FOCUSED_WINDOW);
  75. SwingUtilities.replaceUIInputMap(menuItem, JComponent.
  76. WHEN_IN_FOCUSED_WINDOW, windowInputMap);
  77. }
  78. windowInputMap.put(KeyStroke.getKeyStroke(mnemonic,
  79. ActionEvent.ALT_MASK,
  80. false),
  81. "selectMenu");
  82. }
  83. lastMnemonic = mnemonic;
  84. }
  85. protected void uninstallKeyboardActions() {
  86. super.uninstallKeyboardActions();
  87. }
  88. /**
  89. * The ActionMap for BasicMenUI can not be shared, this is subclassed
  90. * to create a new one for each invocation.
  91. */
  92. ActionMap getActionMap() {
  93. return createActionMap();
  94. }
  95. /**
  96. * Invoked to create the ActionMap.
  97. */
  98. ActionMap createActionMap() {
  99. ActionMap am = super.createActionMap();
  100. if (am != null) {
  101. am.put("selectMenu", new PostAction((JMenu)menuItem, true));
  102. // Get the ActionMap that can be shared.
  103. ActionMap parent = (ActionMap)UIManager.
  104. get("Menu.sharedActionMap");
  105. if (parent == null) {
  106. parent = createSharedActionMap();
  107. if (parent != null) {
  108. UIManager.put("MenuUI.sharedActionMap", parent);
  109. }
  110. }
  111. if (parent != null) {
  112. am.setParent(parent);
  113. }
  114. }
  115. return am;
  116. }
  117. /**
  118. * Creates the ActionMap containing the actions that can be shared.
  119. */
  120. ActionMap createSharedActionMap() {
  121. ActionMap am = new ActionMapUIResource();
  122. am.put("cancel", new CancelAction());
  123. am.put("selectNext", new SelectNextItemAction());
  124. am.put("selectPrevious", new SelectPreviousItemAction());
  125. am.put("selectParent", new SelectParentItemAction());
  126. am.put("selectChild", new SelectChildItemAction());
  127. am.put("return", new ReturnAction());
  128. return am;
  129. }
  130. protected MouseInputListener createMouseInputListener(JComponent c) {
  131. return new MouseInputHandler();
  132. }
  133. protected MenuListener createMenuListener(JComponent c) {
  134. return new MenuHandler();
  135. }
  136. protected ChangeListener createChangeListener(JComponent c) {
  137. return new ChangeHandler((JMenu)c, this);
  138. }
  139. protected PropertyChangeListener createPropertyChangeListener(JComponent c) {
  140. return new PropertyChangeHandler();
  141. }
  142. protected void uninstallDefaults() {
  143. menuItem.setArmed(false);
  144. menuItem.setSelected(false);
  145. menuItem.resetKeyboardActions();
  146. super.uninstallDefaults();
  147. }
  148. protected void uninstallListeners() {
  149. super.uninstallListeners();
  150. menuItem.removeChangeListener(changeListener);
  151. menuItem.removePropertyChangeListener(propertyChangeListener);
  152. ((JMenu)menuItem).removeMenuListener(menuListener);
  153. changeListener = null;
  154. propertyChangeListener = null;
  155. menuListener = null;
  156. }
  157. protected MenuDragMouseListener createMenuDragMouseListener(JComponent c) {
  158. return new MenuDragMouseHandler();
  159. }
  160. protected MenuKeyListener createMenuKeyListener(JComponent c) {
  161. return new MenuKeyHandler();
  162. }
  163. public Dimension getMaximumSize(JComponent c) {
  164. if (((JMenu)menuItem).isTopLevelMenu() == true) {
  165. Dimension d = c.getPreferredSize();
  166. return new Dimension(d.width, Short.MAX_VALUE);
  167. }
  168. return null;
  169. }
  170. protected void setupPostTimer(JMenu menu) {
  171. Timer timer = new Timer(menu.getDelay(),new PostAction(menu,false));
  172. timer.setRepeats(false);
  173. timer.start();
  174. }
  175. private static class PostAction extends AbstractAction {
  176. JMenu menu;
  177. boolean force=false;
  178. PostAction(JMenu menu,boolean shouldForce) {
  179. this.menu = menu;
  180. this.force = shouldForce;
  181. }
  182. public void actionPerformed(ActionEvent e) {
  183. /* Must be commented out to work around compiler bug (4242000)
  184. if (DEBUG) {
  185. System.out.println("In PostAction.actionPerformed");
  186. Thread.dumpStack();
  187. } */
  188. final MenuSelectionManager defaultManager = MenuSelectionManager.defaultManager();
  189. if(force) {
  190. Container cnt = menu.getParent();
  191. if(cnt != null && cnt instanceof JMenuBar) {
  192. final MenuElement me[];
  193. MenuElement subElements[];
  194. subElements = menu.getPopupMenu().getSubElements();
  195. if(subElements.length > 0) {
  196. me = new MenuElement[4];
  197. me[0] = (MenuElement) cnt;
  198. me[1] = (MenuElement) menu;
  199. me[2] = (MenuElement) menu.getPopupMenu();
  200. me[3] = subElements[0];
  201. } else {
  202. me = new MenuElement[3];
  203. me[0] = (MenuElement)cnt;
  204. me[1] = menu;
  205. me[2] = (MenuElement) menu.getPopupMenu();
  206. }
  207. // Clear the path now so that no menu items
  208. // of currently selected menus get a chance
  209. // at this KeyEvent
  210. defaultManager.clearSelectedPath();
  211. defaultManager.setSelectedPath(me);
  212. }
  213. } else {
  214. MenuElement path[] = defaultManager.getSelectedPath();
  215. if(path.length > 0 && path[path.length-1] == menu) {
  216. MenuElement newPath[] = new MenuElement[path.length+1];
  217. System.arraycopy(path,0,newPath,0,path.length);
  218. newPath[path.length] = menu.getPopupMenu();
  219. MenuSelectionManager.defaultManager().setSelectedPath(newPath);
  220. }
  221. }
  222. }
  223. public boolean isEnabled() {
  224. return menu.getModel().isEnabled();
  225. }
  226. }
  227. private class PropertyChangeHandler implements PropertyChangeListener {
  228. public void propertyChange(PropertyChangeEvent e) {
  229. String prop = e.getPropertyName();
  230. if(prop.equals(AbstractButton.MNEMONIC_CHANGED_PROPERTY)) {
  231. updateMnemonicBinding();
  232. }
  233. }
  234. }
  235. private class MouseInputHandler implements MouseInputListener {
  236. public void mouseClicked(MouseEvent e) {}
  237. public void mousePressed(MouseEvent e) {
  238. JMenu menu = (JMenu)menuItem;
  239. if (!menu.isEnabled())
  240. return;
  241. MenuSelectionManager manager =
  242. MenuSelectionManager.defaultManager();
  243. if(menu.isTopLevelMenu()) {
  244. if(menu.isSelected()) {
  245. manager.clearSelectedPath();
  246. } else {
  247. Container cnt = menu.getParent();
  248. if(cnt != null && cnt instanceof JMenuBar) {
  249. MenuElement me[] = new MenuElement[2];
  250. me[0]=(MenuElement)cnt;
  251. me[1]=menu;
  252. manager.setSelectedPath(me);
  253. }
  254. }
  255. }
  256. MenuElement selectedPath[] = manager.getSelectedPath();
  257. if(!(selectedPath.length > 0 &&
  258. selectedPath[selectedPath.length-1] ==
  259. menu.getPopupMenu())) {
  260. if(menu.isTopLevelMenu() ||
  261. menu.getDelay() == 0) {
  262. MenuElement newPath[] = new MenuElement[selectedPath.length+1];
  263. System.arraycopy(selectedPath,0,newPath,0,selectedPath.length);
  264. newPath[selectedPath.length] = menu.getPopupMenu();
  265. manager.setSelectedPath(newPath);
  266. } else {
  267. setupPostTimer(menu);
  268. }
  269. }
  270. }
  271. public void mouseReleased(MouseEvent e) {
  272. JMenu menu = (JMenu)menuItem;
  273. if (!menu.isEnabled())
  274. return;
  275. MenuSelectionManager manager =
  276. MenuSelectionManager.defaultManager();
  277. manager.processMouseEvent(e);
  278. if (!e.isConsumed())
  279. manager.clearSelectedPath();
  280. }
  281. public void mouseEntered(MouseEvent e) {
  282. JMenu menu = (JMenu)menuItem;
  283. if (!menu.isEnabled())
  284. return;
  285. MenuSelectionManager manager =
  286. MenuSelectionManager.defaultManager();
  287. MenuElement selectedPath[] = manager.getSelectedPath();
  288. if (!menu.isTopLevelMenu()) {
  289. if(!(selectedPath.length > 0 &&
  290. selectedPath[selectedPath.length-1] ==
  291. menu.getPopupMenu())) {
  292. if(menu.getDelay() == 0) {
  293. MenuElement newPath[] = new MenuElement[selectedPath.length+2];
  294. System.arraycopy(selectedPath,0,newPath,0,selectedPath.length);
  295. newPath[selectedPath.length] = menuItem;
  296. newPath[selectedPath.length+1] = menu.getPopupMenu();
  297. manager.setSelectedPath(newPath);
  298. } else {
  299. manager.setSelectedPath(getPath());
  300. setupPostTimer(menu);
  301. }
  302. }
  303. } else {
  304. if(selectedPath.length > 0 &&
  305. selectedPath[0] == menu.getParent()) {
  306. MenuElement newPath[] = new MenuElement[3];
  307. // A top level menu's parent is by definition
  308. // a JMenuBar
  309. newPath[0] = (MenuElement)menu.getParent();
  310. newPath[1] = menu;
  311. newPath[2] = menu.getPopupMenu();
  312. manager.setSelectedPath(newPath);
  313. }
  314. }
  315. }
  316. public void mouseExited(MouseEvent e) {
  317. }
  318. public void mouseDragged(MouseEvent e) {
  319. JMenu menu = (JMenu)menuItem;
  320. if (!menu.isEnabled())
  321. return;
  322. MenuSelectionManager.defaultManager().processMouseEvent(e);
  323. }
  324. public void mouseMoved(MouseEvent e) {
  325. }
  326. }
  327. private static class MenuHandler implements MenuListener {
  328. public void menuSelected(MenuEvent e) {}
  329. public void menuDeselected(MenuEvent e) {}
  330. public void menuCanceled(MenuEvent e) {
  331. JMenu m = (JMenu)e.getSource();
  332. MenuSelectionManager manager = MenuSelectionManager.defaultManager();
  333. if(manager.isComponentPartOfCurrentMenu(m))
  334. MenuSelectionManager.defaultManager().clearSelectedPath();
  335. }
  336. }
  337. public class ChangeHandler implements ChangeListener {
  338. public JMenu menu;
  339. public BasicMenuUI ui;
  340. public boolean isSelected = false;
  341. public Component wasFocused;
  342. public ChangeHandler(JMenu m, BasicMenuUI ui) {
  343. menu = m;
  344. this.ui = ui;
  345. validateKeyboardActions(menu.isSelected());
  346. }
  347. public void stateChanged(ChangeEvent e) {
  348. validateKeyboardActions(menu.isSelected());
  349. }
  350. private Component findFocusedComponent(Component c) {
  351. Container parent;
  352. for(parent = c.getParent() ; parent != null ; parent = parent.getParent()) {
  353. if(parent instanceof java.awt.Window)
  354. return ((java.awt.Window)parent).getFocusOwner();
  355. }
  356. return null;
  357. }
  358. private void validateKeyboardActions(boolean sel) {
  359. if(sel != isSelected) {
  360. isSelected = sel;
  361. if(isSelected) {
  362. boolean isRequestFocusEnabled = menu.isRequestFocusEnabled();
  363. wasFocused = findFocusedComponent(menu);
  364. if ((wasFocused instanceof JComponent) &&
  365. ((JComponent)wasFocused).getRootPane() != menu.getRootPane()) {
  366. wasFocused = null;
  367. }
  368. if(!isRequestFocusEnabled)
  369. menu.setRequestFocusEnabled(true);
  370. menu.requestFocus();
  371. if(!isRequestFocusEnabled)
  372. menu.setRequestFocusEnabled(false);
  373. if (selectedWindowInputMap == null) {
  374. Object[] bindings = (Object[])UIManager.get
  375. ("Menu.selectedWindowInputMapBindings");
  376. if (bindings != null) {
  377. selectedWindowInputMap = LookAndFeel.
  378. makeComponentInputMap(menuItem, bindings);
  379. }
  380. }
  381. if (windowInputMap == null) {
  382. windowInputMap = createInputMap(JComponent.
  383. WHEN_IN_FOCUSED_WINDOW);
  384. SwingUtilities.replaceUIInputMap(menuItem, JComponent.
  385. WHEN_IN_FOCUSED_WINDOW,
  386. windowInputMap);
  387. }
  388. if (windowInputMap != null && selectedWindowInputMap != null) {
  389. windowInputMap.setParent(selectedWindowInputMap);
  390. }
  391. } else {
  392. if (windowInputMap != null && selectedWindowInputMap != null) {
  393. windowInputMap.setParent(null);
  394. }
  395. if(wasFocused != null) {
  396. if(wasFocused instanceof JComponent) {
  397. JComponent jc = (JComponent) wasFocused;
  398. boolean isRFEnabled = jc.isRequestFocusEnabled();
  399. if(!isRFEnabled)
  400. jc.setRequestFocusEnabled(true);
  401. wasFocused.requestFocus();
  402. if(!isRFEnabled)
  403. jc.setRequestFocusEnabled(false);
  404. } else
  405. wasFocused.requestFocus();
  406. wasFocused = null;
  407. }
  408. }
  409. }
  410. }
  411. }
  412. private static class CancelAction extends AbstractAction {
  413. public void actionPerformed(ActionEvent e) {
  414. /* Must be commented out to work around compiler bug (4242000)
  415. if (DEBUG) {
  416. System.out.println("In CancelAction.actionPerformed");
  417. Thread.dumpStack();
  418. }
  419. */
  420. JMenu menu = (JMenu)e.getSource();
  421. if (!menu.isEnabled())
  422. return;
  423. MenuElement path[] = MenuSelectionManager.defaultManager().getSelectedPath();
  424. if(path.length > 4) { /* PENDING(arnaud) Change this to 2 when a mouse grabber is available for MenuBar */
  425. MenuElement newPath[] = new MenuElement[path.length - 2];
  426. System.arraycopy(path,0,newPath,0,path.length-2);
  427. MenuSelectionManager.defaultManager().setSelectedPath(newPath);
  428. } else
  429. MenuSelectionManager.defaultManager().clearSelectedPath();
  430. }
  431. }
  432. private class ReturnAction extends AbstractAction {
  433. public void actionPerformed(ActionEvent e) {
  434. JMenu menu = (JMenu)e.getSource();
  435. if (!menu.isEnabled())
  436. return;
  437. MenuElement path[] = MenuSelectionManager.defaultManager().getSelectedPath();
  438. MenuElement lastElement;
  439. if(path.length > 0) {
  440. lastElement = path[path.length-1];
  441. if(lastElement instanceof JMenu) {
  442. MenuElement newPath[] = new MenuElement[path.length+1];
  443. System.arraycopy(path,0,newPath,0,path.length);
  444. newPath[path.length] = ((JMenu)lastElement).getPopupMenu();
  445. MenuSelectionManager.defaultManager().setSelectedPath(newPath);
  446. } else if(lastElement instanceof JMenuItem) {
  447. MenuSelectionManager.defaultManager().clearSelectedPath();
  448. ((JMenuItem)lastElement).doClick(0);
  449. ((JMenuItem)lastElement).setArmed(false);
  450. }
  451. }
  452. }
  453. }
  454. private static MenuElement nextEnabledChild(MenuElement e[],int fromIndex) {
  455. int i,c;
  456. for(i=fromIndex,c=e.length ; i < c ; i++) {
  457. if (e[i]!=null) {
  458. Component comp = e[i].getComponent();
  459. if(comp != null && comp.isEnabled())
  460. return e[i];
  461. }
  462. }
  463. return null;
  464. }
  465. private static MenuElement previousEnabledChild(MenuElement e[],int fromIndex) {
  466. int i;
  467. for(i=fromIndex ; i >= 0 ; i--) {
  468. if (e[i]!=null) {
  469. Component comp = e[i].getComponent();
  470. if(comp != null && comp.isEnabled())
  471. return e[i];
  472. }
  473. }
  474. return null;
  475. }
  476. private static class SelectNextItemAction extends AbstractAction {
  477. public void actionPerformed(ActionEvent e) {
  478. /* Must be commented out to work around compiler bug (4242000)
  479. if (DEBUG) {
  480. System.out.println("In SelectNextItemAction.actionPerformed");
  481. }
  482. */
  483. JMenu menu = (JMenu)e.getSource();
  484. if (!menu.isEnabled())
  485. return;
  486. MenuElement currentSelection[] = MenuSelectionManager.defaultManager().getSelectedPath();
  487. if(currentSelection.length > 1) {
  488. MenuElement parent = currentSelection[currentSelection.length-2];
  489. if(parent.getComponent() instanceof JMenu) {
  490. MenuElement childs[];
  491. parent = currentSelection[currentSelection.length-1];
  492. childs = parent.getSubElements();
  493. if(childs.length > 0) {
  494. MenuElement newPath[] = new MenuElement[currentSelection.length+1];
  495. System.arraycopy(currentSelection,0,
  496. newPath,0,currentSelection.length);
  497. newPath[currentSelection.length] = nextEnabledChild(childs,0);
  498. if(newPath[currentSelection.length] != null) {
  499. MenuSelectionManager.defaultManager().setSelectedPath(newPath);
  500. }
  501. }
  502. } else {
  503. MenuElement childs[] = parent.getSubElements();
  504. MenuElement nextChild;
  505. int i,c;
  506. for(i=0,c=childs.length;i<c;i++) {
  507. if(childs[i] == currentSelection[currentSelection.length-1]) {
  508. nextChild = nextEnabledChild(childs,i+1);
  509. if(nextChild == null)
  510. nextChild = nextEnabledChild(childs,0);
  511. if(nextChild != null) {
  512. currentSelection[currentSelection.length-1] = nextChild;
  513. MenuSelectionManager.defaultManager().setSelectedPath(currentSelection);
  514. }
  515. break;
  516. }
  517. }
  518. }
  519. }
  520. }
  521. }
  522. private static class SelectPreviousItemAction extends AbstractAction {
  523. public void actionPerformed(ActionEvent e) {
  524. /* Must be commented out to work around compiler bug (4242000)
  525. if (DEBUG) {
  526. System.out.println("In SelectPreviousItemAction.actionPerformed");
  527. }
  528. */
  529. JMenu menu = (JMenu)e.getSource();
  530. if (!menu.isEnabled())
  531. return;
  532. MenuElement currentSelection[] = MenuSelectionManager.defaultManager().getSelectedPath();
  533. if(currentSelection.length > 1) {
  534. MenuElement parent = currentSelection[currentSelection.length-2];
  535. if(parent.getComponent() instanceof JMenu) {
  536. MenuElement childs[];
  537. parent = currentSelection[currentSelection.length-1];
  538. childs = parent.getSubElements();
  539. if(childs.length > 0) {
  540. MenuElement newPath[] = new MenuElement[currentSelection.length+1];
  541. System.arraycopy(currentSelection,0,
  542. newPath,0,currentSelection.length);
  543. newPath[currentSelection.length] = previousEnabledChild(childs,childs.length-1);
  544. if(newPath[currentSelection.length] != null)
  545. MenuSelectionManager.defaultManager().setSelectedPath(newPath);
  546. }
  547. } else {
  548. MenuElement childs[] = parent.getSubElements();
  549. MenuElement nextChild;
  550. int i,c;
  551. for(i=0,c=childs.length;i<c;i++) {
  552. if(childs[i] == currentSelection[currentSelection.length-1]) {
  553. nextChild = previousEnabledChild(childs,i-1);
  554. if(nextChild == null)
  555. nextChild = previousEnabledChild(childs,childs.length-1);
  556. if(nextChild != null) {
  557. currentSelection[currentSelection.length-1] = nextChild;
  558. MenuSelectionManager.defaultManager().setSelectedPath(currentSelection);
  559. }
  560. break;
  561. }
  562. }
  563. }
  564. }
  565. }
  566. }
  567. private static class SelectParentItemAction extends AbstractAction {
  568. public void actionPerformed(ActionEvent e) {
  569. JMenu menu = (JMenu)e.getSource();
  570. if (!menu.isEnabled())
  571. return;
  572. MenuElement path[] = MenuSelectionManager.defaultManager().getSelectedPath();
  573. if(path.length > 3 && path[path.length-3].getComponent() instanceof JMenu &&
  574. !((JMenu)path[path.length-3].getComponent()).isTopLevelMenu()) {
  575. MenuElement newPath[] = new MenuElement[path.length-2];
  576. System.arraycopy(path,0,newPath,0,path.length-2);
  577. MenuSelectionManager.defaultManager().setSelectedPath(newPath);
  578. } else if(path.length > 0 && path[0].getComponent() instanceof JMenuBar) {
  579. MenuElement nextMenu=null,popup=null,firstItem=null;
  580. MenuElement tmp[];
  581. int i,c;
  582. if(path.length > 1) {
  583. MenuElement previousElement;
  584. tmp = path[0].getSubElements();
  585. for(i=0,c=tmp.length;i<c;i++) {
  586. if(tmp[i] == path[1]) {
  587. nextMenu = previousEnabledChild(tmp,i-1);
  588. if(nextMenu == null)
  589. nextMenu = previousEnabledChild(tmp,tmp.length-1);
  590. }
  591. }
  592. }
  593. if(nextMenu != null) {
  594. MenuElement newSelection[];
  595. popup = ((JMenu)nextMenu).getPopupMenu();
  596. if(((JMenu)nextMenu).isTopLevelMenu())
  597. firstItem = null;
  598. else {
  599. tmp = popup.getSubElements();
  600. if(tmp.length > 0)
  601. firstItem = nextEnabledChild(tmp,0);
  602. }
  603. if(firstItem != null) {
  604. newSelection = new MenuElement[4];
  605. newSelection[0] = path[0];
  606. newSelection[1] = nextMenu;
  607. newSelection[2] = popup;
  608. newSelection[3] = firstItem;
  609. } else {
  610. newSelection = new MenuElement[3];
  611. newSelection[0] = path[0];
  612. newSelection[1] = nextMenu;
  613. newSelection[2] = popup;
  614. }
  615. MenuSelectionManager.defaultManager().setSelectedPath(newSelection);
  616. }
  617. }
  618. }
  619. }
  620. private static class SelectChildItemAction extends AbstractAction {
  621. public void actionPerformed(ActionEvent e) {
  622. JMenu menu = (JMenu)e.getSource();
  623. if (!menu.isEnabled())
  624. return;
  625. MenuElement path[] = MenuSelectionManager.defaultManager().getSelectedPath();
  626. if(path.length > 0 && path[path.length-1].getComponent().isEnabled() &&
  627. path[path.length-1].getComponent() instanceof JMenu &&
  628. !((JMenu)path[path.length-1].getComponent()).isTopLevelMenu()) {
  629. MenuElement newPath[] = new MenuElement[path.length+2];
  630. MenuElement subElements[];
  631. System.arraycopy(path,0,newPath,0,path.length);
  632. newPath[path.length] = ((JMenu)path[path.length-1].getComponent()).getPopupMenu();
  633. subElements = newPath[path.length].getSubElements();
  634. if(subElements.length > 0) {
  635. newPath[path.length+1] = nextEnabledChild(subElements,0);
  636. MenuSelectionManager.defaultManager().setSelectedPath(newPath);
  637. }
  638. } else if(path.length > 0 && path[0].getComponent() instanceof JMenuBar) {
  639. MenuElement nextMenu=null,popup=null,firstItem=null;
  640. MenuElement tmp[];
  641. int i,c;
  642. if(path.length > 1) {
  643. tmp = path[0].getSubElements();
  644. for(i=0,c=tmp.length;i<c;i++) {
  645. if(tmp[i] == path[1]) {
  646. nextMenu = nextEnabledChild(tmp,i+1);
  647. if(nextMenu == null)
  648. nextMenu = nextEnabledChild(tmp,0);
  649. }
  650. }
  651. }
  652. if(nextMenu != null) {
  653. MenuElement newSelection[];
  654. popup = ((JMenu)nextMenu).getPopupMenu();
  655. if(((JMenu)nextMenu).isTopLevelMenu())
  656. firstItem = null;
  657. else {
  658. tmp = popup.getSubElements();
  659. if(tmp.length > 0)
  660. firstItem = nextEnabledChild(tmp,0);
  661. }
  662. if(firstItem != null) {
  663. newSelection = new MenuElement[4];
  664. newSelection[0] = path[0];
  665. newSelection[1] = nextMenu;
  666. newSelection[2] = popup;
  667. newSelection[3] = firstItem;
  668. } else {
  669. newSelection = new MenuElement[3];
  670. newSelection[0] = path[0];
  671. newSelection[1] = nextMenu;
  672. newSelection[2] = popup;
  673. }
  674. MenuSelectionManager.defaultManager().setSelectedPath(newSelection);
  675. }
  676. }
  677. }
  678. }
  679. private class MenuDragMouseHandler implements MenuDragMouseListener {
  680. public void menuDragMouseEntered(MenuDragMouseEvent e) {}
  681. public void menuDragMouseDragged(MenuDragMouseEvent e) {
  682. if (menuItem.isEnabled() == false)
  683. return;
  684. MenuSelectionManager manager = e.getMenuSelectionManager();
  685. MenuElement path[] = e.getPath();
  686. Point p = e.getPoint();
  687. if(p.x >= 0 && p.x < menuItem.getWidth() &&
  688. p.y >= 0 && p.y < menuItem.getHeight()) {
  689. JMenu menu = (JMenu)menuItem;
  690. MenuElement selectedPath[] = manager.getSelectedPath();
  691. if(!(selectedPath.length > 0 &&
  692. selectedPath[selectedPath.length-1] ==
  693. menu.getPopupMenu())) {
  694. if(menu.isTopLevelMenu() ||
  695. menu.getDelay() == 0 ||
  696. e.getID() == MouseEvent.MOUSE_DRAGGED) {
  697. MenuElement newPath[] = new MenuElement[path.length+1];
  698. System.arraycopy(path,0,newPath,0,path.length);
  699. newPath[path.length] = menu.getPopupMenu();
  700. manager.setSelectedPath(newPath);
  701. } else {
  702. manager.setSelectedPath(path);
  703. setupPostTimer(menu);
  704. }
  705. }
  706. } else if(e.getID() == MouseEvent.MOUSE_RELEASED) {
  707. Component comp = manager.componentForPoint(e.getComponent(), e.getPoint());
  708. if (comp == null)
  709. manager.clearSelectedPath();
  710. }
  711. }
  712. public void menuDragMouseExited(MenuDragMouseEvent e) {}
  713. public void menuDragMouseReleased(MenuDragMouseEvent e) {}
  714. }
  715. private class MenuKeyHandler implements MenuKeyListener {
  716. public void menuKeyTyped(MenuKeyEvent e) {
  717. int key = menuItem.getMnemonic();
  718. if(key == 0)
  719. return;
  720. MenuElement path[] = e.getPath();
  721. if(lower(key) == lower((int)(e.getKeyChar()))) {
  722. JPopupMenu popupMenu = ((JMenu)menuItem).getPopupMenu();
  723. MenuElement sub[] = popupMenu.getSubElements();
  724. if(sub.length > 0) {
  725. MenuSelectionManager manager = e.getMenuSelectionManager();
  726. MenuElement newPath[] = new MenuElement[path.length + 2];
  727. System.arraycopy(path,0,newPath,0,path.length);
  728. newPath[path.length] = popupMenu;
  729. newPath[path.length+1] = sub[0];
  730. manager.setSelectedPath(newPath);
  731. }
  732. e.consume();
  733. }
  734. }
  735. public void menuKeyPressed(MenuKeyEvent e) {}
  736. public void menuKeyReleased(MenuKeyEvent e) {}
  737. private int lower(int ascii) {
  738. if(ascii >= 'A' && ascii <= 'Z')
  739. return ascii + 'a' - 'A';
  740. else
  741. return ascii;
  742. }
  743. }
  744. }