1. /*
  2. * @(#)BasicMenuItemUI.java 1.88 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 java.awt.*;
  9. import java.awt.event.*;
  10. import java.beans.PropertyChangeEvent;
  11. import java.beans.PropertyChangeListener;
  12. import javax.swing.*;
  13. import javax.swing.event.*;
  14. import javax.swing.border.*;
  15. import javax.swing.plaf.*;
  16. import javax.swing.text.View;
  17. /**
  18. * BasicMenuItem implementation
  19. *
  20. * @version 1.88 11/29/01
  21. * @author Georges Saab
  22. * @author David Karlton
  23. * @author Arnaud Weber
  24. */
  25. public class BasicMenuItemUI extends MenuItemUI
  26. {
  27. protected JMenuItem menuItem = null;
  28. protected Color selectionBackground;
  29. protected Color selectionForeground;
  30. protected Color disabledForeground;
  31. protected Color acceleratorForeground;
  32. protected Color acceleratorSelectionForeground;
  33. private String acceleratorDelimiter;
  34. protected int defaultTextIconGap;
  35. protected Font acceleratorFont;
  36. protected MouseInputListener mouseInputListener;
  37. protected MenuDragMouseListener menuDragMouseListener;
  38. protected MenuKeyListener menuKeyListener;
  39. private PropertyChangeListener propertyChangeListener;
  40. protected Icon arrowIcon = null;
  41. protected Icon checkIcon = null;
  42. protected boolean oldBorderPainted;
  43. public static ComponentUI createUI(JComponent c) {
  44. return new BasicMenuItemUI();
  45. }
  46. public void installUI(JComponent c) {
  47. menuItem = (JMenuItem) c;
  48. installDefaults();
  49. installComponents();
  50. installListeners();
  51. installKeyboardActions();
  52. }
  53. protected void installDefaults() {
  54. String prefix = getPropertyPrefix();
  55. acceleratorFont = UIManager.getFont("MenuItem.acceleratorFont");
  56. menuItem.setOpaque(true);
  57. if(menuItem.getMargin() == null ||
  58. (menuItem.getMargin() instanceof UIResource)) {
  59. menuItem.setMargin(UIManager.getInsets(prefix + ".margin"));
  60. }
  61. defaultTextIconGap = 4; // Should be from table
  62. LookAndFeel.installBorder(menuItem, prefix + ".border");
  63. oldBorderPainted = menuItem.isBorderPainted();
  64. menuItem.setBorderPainted( ( (Boolean) (UIManager.get(prefix + ".borderPainted")) ).booleanValue() );
  65. LookAndFeel.installColorsAndFont(menuItem,
  66. prefix + ".background",
  67. prefix + ".foreground",
  68. prefix + ".font");
  69. // MenuItem specific defaults
  70. if (selectionBackground == null ||
  71. selectionBackground instanceof UIResource) {
  72. selectionBackground =
  73. UIManager.getColor(prefix + ".selectionBackground");
  74. }
  75. if (selectionForeground == null ||
  76. selectionForeground instanceof UIResource) {
  77. selectionForeground =
  78. UIManager.getColor(prefix + ".selectionForeground");
  79. }
  80. if (disabledForeground == null ||
  81. disabledForeground instanceof UIResource) {
  82. disabledForeground =
  83. UIManager.getColor(prefix + ".disabledForeground");
  84. }
  85. if (acceleratorForeground == null ||
  86. acceleratorForeground instanceof UIResource) {
  87. acceleratorForeground =
  88. UIManager.getColor(prefix + ".acceleratorForeground");
  89. }
  90. if (acceleratorSelectionForeground == null ||
  91. acceleratorSelectionForeground instanceof UIResource) {
  92. acceleratorSelectionForeground =
  93. UIManager.getColor(prefix + ".acceleratorSelectionForeground");
  94. }
  95. // Get accelerator delimiter
  96. acceleratorDelimiter =
  97. UIManager.getString("MenuItem.acceleratorDelimiter");
  98. if (acceleratorDelimiter == null) { acceleratorDelimiter = "+"; }
  99. // Icons
  100. if (arrowIcon == null ||
  101. arrowIcon instanceof UIResource) {
  102. arrowIcon = UIManager.getIcon(prefix + ".arrowIcon");
  103. }
  104. if (checkIcon == null ||
  105. checkIcon instanceof UIResource) {
  106. checkIcon = UIManager.getIcon(prefix + ".checkIcon");
  107. }
  108. }
  109. /* Unfortunately this has to remain private until we can make API additions.
  110. */
  111. private void installComponents(){
  112. BasicHTML.updateRenderer(menuItem, menuItem.getText());
  113. }
  114. protected String getPropertyPrefix() {
  115. return "MenuItem";
  116. }
  117. protected void installListeners() {
  118. mouseInputListener = createMouseInputListener(menuItem);
  119. menuDragMouseListener = createMenuDragMouseListener(menuItem);
  120. menuKeyListener = createMenuKeyListener(menuItem);
  121. propertyChangeListener = createPropertyChangeListener(menuItem);
  122. menuItem.addMouseListener(mouseInputListener);
  123. menuItem.addMouseMotionListener(mouseInputListener);
  124. menuItem.addMenuDragMouseListener(menuDragMouseListener);
  125. menuItem.addMenuKeyListener(menuKeyListener);
  126. menuItem.addPropertyChangeListener(propertyChangeListener);
  127. }
  128. protected void installKeyboardActions() {}
  129. public void uninstallUI(JComponent c) {
  130. uninstallDefaults();
  131. uninstallComponents();
  132. uninstallListeners();
  133. uninstallKeyboardActions();
  134. menuItem = null;
  135. }
  136. protected void uninstallDefaults() {
  137. LookAndFeel.uninstallBorder(menuItem);
  138. menuItem.setBorderPainted( oldBorderPainted );
  139. if (arrowIcon instanceof UIResource)
  140. arrowIcon = null;
  141. if (checkIcon instanceof UIResource)
  142. checkIcon = null;
  143. }
  144. /* Unfortunately this has to remain private until we can make API additions.
  145. */
  146. private void uninstallComponents(){
  147. BasicHTML.updateRenderer(menuItem, "");
  148. }
  149. protected void uninstallListeners() {
  150. menuItem.removeMouseListener(mouseInputListener);
  151. menuItem.removeMouseMotionListener(mouseInputListener);
  152. menuItem.removeMenuDragMouseListener(menuDragMouseListener);
  153. menuItem.removeMenuKeyListener(menuKeyListener);
  154. menuItem.removePropertyChangeListener(propertyChangeListener);
  155. mouseInputListener = null;
  156. menuDragMouseListener = null;
  157. menuKeyListener = null;
  158. propertyChangeListener = null;
  159. }
  160. protected void uninstallKeyboardActions() {}
  161. protected MouseInputListener createMouseInputListener(JComponent c) {
  162. return new MouseInputHandler();
  163. }
  164. protected MenuDragMouseListener createMenuDragMouseListener(JComponent c) {
  165. return new MenuDragMouseHandler();
  166. }
  167. protected MenuKeyListener createMenuKeyListener(JComponent c) {
  168. return new MenuKeyHandler();
  169. }
  170. private PropertyChangeListener createPropertyChangeListener(JComponent c) {
  171. return new PropertyChangeHandler();
  172. }
  173. public Dimension getMinimumSize(JComponent c) {
  174. Dimension d = null;
  175. View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  176. if (v != null) {
  177. d = getPreferredSize(c);
  178. d.width -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS);
  179. }
  180. return d;
  181. }
  182. public Dimension getPreferredSize(JComponent c) {
  183. return getPreferredMenuItemSize(c,
  184. checkIcon,
  185. arrowIcon,
  186. defaultTextIconGap);
  187. }
  188. public Dimension getMaximumSize(JComponent c) {
  189. Dimension d = null;
  190. View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  191. if (v != null) {
  192. d = getPreferredSize(c);
  193. d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS);
  194. }
  195. return d;
  196. }
  197. // these rects are used for painting and preferredsize calculations.
  198. // they used to be regenerated constantly. Now they are reused.
  199. static Rectangle zeroRect = new Rectangle(0,0,0,0);
  200. static Rectangle iconRect = new Rectangle();
  201. static Rectangle textRect = new Rectangle();
  202. static Rectangle acceleratorRect = new Rectangle();
  203. static Rectangle checkIconRect = new Rectangle();
  204. static Rectangle arrowIconRect = new Rectangle();
  205. static Rectangle viewRect = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE);
  206. static Rectangle r = new Rectangle();
  207. private void resetRects() {
  208. iconRect.setBounds(zeroRect);
  209. textRect.setBounds(zeroRect);
  210. acceleratorRect.setBounds(zeroRect);
  211. checkIconRect.setBounds(zeroRect);
  212. arrowIconRect.setBounds(zeroRect);
  213. viewRect.setBounds(0,0,Short.MAX_VALUE, Short.MAX_VALUE);
  214. r.setBounds(zeroRect);
  215. }
  216. protected Dimension getPreferredMenuItemSize(JComponent c,
  217. Icon checkIcon,
  218. Icon arrowIcon,
  219. int defaultTextIconGap) {
  220. JMenuItem b = (JMenuItem) c;
  221. Icon icon = (Icon) b.getIcon();
  222. String text = b.getText();
  223. KeyStroke accelerator = b.getAccelerator();
  224. String acceleratorText = "";
  225. if (accelerator != null) {
  226. int modifiers = accelerator.getModifiers();
  227. if (modifiers > 0) {
  228. acceleratorText = KeyEvent.getKeyModifiersText(modifiers);
  229. //acceleratorText += "-";
  230. acceleratorText += acceleratorDelimiter;
  231. }
  232. acceleratorText += KeyEvent.getKeyText(accelerator.getKeyCode());
  233. }
  234. Font font = b.getFont();
  235. FontMetrics fm = b.getToolkit().getFontMetrics(font);
  236. FontMetrics fmAccel = b.getToolkit().getFontMetrics( acceleratorFont );
  237. resetRects();
  238. layoutMenuItem(
  239. fm, text, fmAccel, acceleratorText, icon, checkIcon, arrowIcon,
  240. b.getVerticalAlignment(), b.getHorizontalAlignment(),
  241. b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
  242. viewRect, iconRect, textRect, acceleratorRect, checkIconRect, arrowIconRect,
  243. text == null ? 0 : defaultTextIconGap,
  244. defaultTextIconGap
  245. );
  246. // find the union of the icon and text rects
  247. r.setBounds(textRect);
  248. r = SwingUtilities.computeUnion(iconRect.x,
  249. iconRect.y,
  250. iconRect.width,
  251. iconRect.height,
  252. r);
  253. // r = iconRect.union(textRect);
  254. // Add in the accelerator
  255. boolean acceleratorTextIsEmpty = (acceleratorText == null) ||
  256. acceleratorText.equals("");
  257. if (!acceleratorTextIsEmpty) {
  258. r.width += acceleratorRect.width;
  259. r.width += 7*defaultTextIconGap;
  260. }
  261. if( useCheckAndArrow() ) {
  262. // Add in the checkIcon
  263. r.width += checkIconRect.width;
  264. r.width += defaultTextIconGap;
  265. // Add in the arrowIcon
  266. r.width += defaultTextIconGap;
  267. r.width += arrowIconRect.width;
  268. }
  269. r.width += 2*defaultTextIconGap;
  270. Insets insets = b.getInsets();
  271. if(insets != null) {
  272. r.width += insets.left + insets.right;
  273. r.height += insets.top + insets.bottom;
  274. }
  275. // if the width is even, bump it up one. This is critical
  276. // for the focus dash line to draw properly
  277. if(r.width%2 == 0) {
  278. r.width++;
  279. }
  280. // if the height is even, bump it up one. This is critical
  281. // for the text to center properly
  282. if(r.height%2 == 0) {
  283. r.height++;
  284. }
  285. return r.getSize();
  286. }
  287. /**
  288. * We draw the background in paintMenuItem()
  289. * so override update (which fills the background of opaque
  290. * components by default) to just call paint().
  291. *
  292. */
  293. public void update(Graphics g, JComponent c) {
  294. paint(g, c);
  295. }
  296. public void paint(Graphics g, JComponent c) {
  297. paintMenuItem(g, c, checkIcon, arrowIcon,
  298. selectionBackground, selectionForeground,
  299. defaultTextIconGap);
  300. }
  301. protected void paintMenuItem(Graphics g, JComponent c,
  302. Icon checkIcon, Icon arrowIcon,
  303. Color background, Color foreground,
  304. int defaultTextIconGap) {
  305. JMenuItem b = (JMenuItem) c;
  306. ButtonModel model = b.getModel();
  307. // Dimension size = b.getSize();
  308. int menuWidth = b.getWidth();
  309. int menuHeight = b.getHeight();
  310. Insets i = c.getInsets();
  311. resetRects();
  312. viewRect.setBounds( 0, 0, menuWidth, menuHeight );
  313. viewRect.x += i.left;
  314. viewRect.y += i.top;
  315. viewRect.width -= (i.right + viewRect.x);
  316. viewRect.height -= (i.bottom + viewRect.y);
  317. Font holdf = g.getFont();
  318. Font f = c.getFont();
  319. g.setFont( f );
  320. FontMetrics fm = g.getFontMetrics( f );
  321. FontMetrics fmAccel = g.getFontMetrics( acceleratorFont );
  322. // Paint background
  323. Color holdc = g.getColor();
  324. if(c.isOpaque()) {
  325. if (model.isArmed()|| (c instanceof JMenu && model.isSelected())) {
  326. g.setColor(background);
  327. g.fillRect(0,0, menuWidth, menuHeight);
  328. } else {
  329. g.setColor(b.getBackground());
  330. g.fillRect(0,0, menuWidth, menuHeight);
  331. }
  332. g.setColor(holdc);
  333. }
  334. // get Accelerator text
  335. KeyStroke accelerator = b.getAccelerator();
  336. String acceleratorText = "";
  337. if (accelerator != null) {
  338. int modifiers = accelerator.getModifiers();
  339. if (modifiers > 0) {
  340. acceleratorText = KeyEvent.getKeyModifiersText(modifiers);
  341. //acceleratorText += "-";
  342. acceleratorText += acceleratorDelimiter;
  343. }
  344. acceleratorText += KeyEvent.getKeyText(accelerator.getKeyCode());
  345. }
  346. // layout the text and icon
  347. String text = layoutMenuItem(
  348. fm, b.getText(), fmAccel, acceleratorText, b.getIcon(),
  349. checkIcon, arrowIcon,
  350. b.getVerticalAlignment(), b.getHorizontalAlignment(),
  351. b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
  352. viewRect, iconRect, textRect, acceleratorRect,
  353. checkIconRect, arrowIconRect,
  354. b.getText() == null ? 0 : defaultTextIconGap,
  355. defaultTextIconGap
  356. );
  357. // Paint the Check
  358. if (checkIcon != null) {
  359. if(model.isArmed() || (c instanceof JMenu && model.isSelected())) {
  360. g.setColor(foreground);
  361. } else {
  362. g.setColor(b.getForeground());
  363. }
  364. if( useCheckAndArrow() )
  365. checkIcon.paintIcon(c, g, checkIconRect.x, checkIconRect.y);
  366. g.setColor(holdc);
  367. }
  368. // Paint the Icon
  369. if(b.getIcon() != null) {
  370. Icon icon;
  371. if(!model.isEnabled()) {
  372. icon = (Icon) b.getDisabledIcon();
  373. } else if(model.isPressed() && model.isArmed()) {
  374. icon = (Icon) b.getPressedIcon();
  375. if(icon == null) {
  376. // Use default icon
  377. icon = (Icon) b.getIcon();
  378. }
  379. } else {
  380. icon = (Icon) b.getIcon();
  381. }
  382. if (icon!=null)
  383. icon.paintIcon(c, g, iconRect.x, iconRect.y);
  384. }
  385. // Draw the Text
  386. if(text != null) {
  387. View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  388. if (v != null) {
  389. v.paint(g, textRect);
  390. } else {
  391. if(!model.isEnabled()) {
  392. // *** paint the text disabled
  393. if ( UIManager.get("MenuItem.disabledForeground") instanceof Color )
  394. {
  395. g.setColor( UIManager.getColor("MenuItem.disabledForeground") );
  396. BasicGraphicsUtils.drawString(g,text,model.getMnemonic(),
  397. textRect.x, textRect.y + fm.getAscent());
  398. }
  399. else
  400. {
  401. g.setColor(b.getBackground().brighter());
  402. BasicGraphicsUtils.drawString(g,text,model.getMnemonic(),
  403. textRect.x, textRect.y + fm.getAscent());
  404. g.setColor(b.getBackground().darker());
  405. BasicGraphicsUtils.drawString(g,text,model.getMnemonic(),
  406. textRect.x - 1, textRect.y + fm.getAscent() - 1);
  407. }
  408. } else {
  409. // *** paint the text normally
  410. if (model.isArmed()|| (c instanceof JMenu && model.isSelected())) {
  411. g.setColor(foreground);
  412. } else {
  413. g.setColor(b.getForeground());
  414. }
  415. BasicGraphicsUtils.drawString(g,text,
  416. model.getMnemonic(),
  417. textRect.x,
  418. textRect.y + fm.getAscent());
  419. }
  420. }
  421. }
  422. // Draw the Accelerator Text
  423. if(acceleratorText != null && !acceleratorText.equals("")) {
  424. g.setFont( acceleratorFont );
  425. if(!model.isEnabled()) {
  426. // *** paint the acceleratorText disabled
  427. if ( disabledForeground != null )
  428. {
  429. g.setColor( disabledForeground );
  430. BasicGraphicsUtils.drawString(g,acceleratorText,0,
  431. acceleratorRect.x,
  432. acceleratorRect.y + fmAccel.getAscent());
  433. }
  434. else
  435. {
  436. g.setColor(b.getBackground().brighter());
  437. BasicGraphicsUtils.drawString(g,acceleratorText,0,
  438. acceleratorRect.x, acceleratorRect.y + fmAccel.getAscent());
  439. g.setColor(b.getBackground().darker());
  440. BasicGraphicsUtils.drawString(g,acceleratorText,0,
  441. acceleratorRect.x - 1, acceleratorRect.y + fmAccel.getAscent() - 1);
  442. }
  443. } else {
  444. // *** paint the acceleratorText normally
  445. if (model.isArmed()|| (c instanceof JMenu && model.isSelected())) {
  446. g.setColor( acceleratorSelectionForeground );
  447. } else {
  448. g.setColor( acceleratorForeground );
  449. }
  450. BasicGraphicsUtils.drawString(g,acceleratorText, 0,
  451. acceleratorRect.x,
  452. acceleratorRect.y + fmAccel.getAscent());
  453. }
  454. }
  455. // Paint the Arrow
  456. if (arrowIcon != null) {
  457. if(model.isArmed() || (c instanceof JMenu &&model.isSelected()))
  458. g.setColor(foreground);
  459. if(useCheckAndArrow())
  460. arrowIcon.paintIcon(c, g, arrowIconRect.x, arrowIconRect.y);
  461. }
  462. g.setColor(holdc);
  463. g.setFont(holdf);
  464. }
  465. /**
  466. * Compute and return the location of the icons origin, the
  467. * location of origin of the text baseline, and a possibly clipped
  468. * version of the compound labels string. Locations are computed
  469. * relative to the viewRect rectangle.
  470. */
  471. private String layoutMenuItem(
  472. FontMetrics fm,
  473. String text,
  474. FontMetrics fmAccel,
  475. String acceleratorText,
  476. Icon icon,
  477. Icon checkIcon,
  478. Icon arrowIcon,
  479. int verticalAlignment,
  480. int horizontalAlignment,
  481. int verticalTextPosition,
  482. int horizontalTextPosition,
  483. Rectangle viewRect,
  484. Rectangle iconRect,
  485. Rectangle textRect,
  486. Rectangle acceleratorRect,
  487. Rectangle checkIconRect,
  488. Rectangle arrowIconRect,
  489. int textIconGap,
  490. int menuItemGap
  491. )
  492. {
  493. SwingUtilities.layoutCompoundLabel(
  494. menuItem, fm, text, icon, verticalAlignment,
  495. horizontalAlignment, verticalTextPosition,
  496. horizontalTextPosition, viewRect, iconRect, textRect,
  497. textIconGap);
  498. /* Initialize the acceelratorText bounds rectangle textRect. If a null
  499. * or and empty String was specified we substitute "" here
  500. * and use 0,0,0,0 for acceleratorTextRect.
  501. */
  502. if( (acceleratorText == null) || acceleratorText.equals("") ) {
  503. acceleratorRect.width = acceleratorRect.height = 0;
  504. acceleratorText = "";
  505. }
  506. else {
  507. acceleratorRect.width = SwingUtilities.computeStringWidth( fmAccel, acceleratorText );
  508. acceleratorRect.height = fmAccel.getHeight();
  509. }
  510. /* Initialize the checkIcon bounds rectangle's width & height.
  511. */
  512. if( useCheckAndArrow()) {
  513. if (checkIcon != null) {
  514. checkIconRect.width = checkIcon.getIconWidth();
  515. checkIconRect.height = checkIcon.getIconHeight();
  516. }
  517. else {
  518. checkIconRect.width = checkIconRect.height = 0;
  519. }
  520. /* Initialize the arrowIcon bounds rectangle width & height.
  521. */
  522. if (arrowIcon != null) {
  523. arrowIconRect.width = arrowIcon.getIconWidth();
  524. arrowIconRect.height = arrowIcon.getIconHeight();
  525. } else {
  526. arrowIconRect.width = arrowIconRect.height = 0;
  527. }
  528. }
  529. Rectangle labelRect = iconRect.union(textRect);
  530. if( BasicGraphicsUtils.isLeftToRight(menuItem) ) {
  531. textRect.x += menuItemGap;
  532. iconRect.x += menuItemGap;
  533. // Position the Accelerator text rect
  534. acceleratorRect.x = viewRect.x + viewRect.width - arrowIconRect.width
  535. - menuItemGap - acceleratorRect.width;
  536. // Position the Check and Arrow Icons
  537. if (useCheckAndArrow()) {
  538. checkIconRect.x = viewRect.x + menuItemGap;
  539. textRect.x += menuItemGap + checkIconRect.width;
  540. iconRect.x += menuItemGap + checkIconRect.width;
  541. arrowIconRect.x = viewRect.x + viewRect.width - menuItemGap
  542. - arrowIconRect.width;
  543. }
  544. } else {
  545. textRect.x -= menuItemGap;
  546. iconRect.x -= menuItemGap;
  547. // Position the Accelerator text rect
  548. acceleratorRect.x = viewRect.x + arrowIconRect.width + menuItemGap;
  549. // Position the Check and Arrow Icons
  550. if (useCheckAndArrow()) {
  551. checkIconRect.x = viewRect.x + viewRect.width - menuItemGap
  552. - checkIconRect.width;
  553. textRect.x -= menuItemGap + checkIconRect.width;
  554. iconRect.x -= menuItemGap + checkIconRect.width;
  555. arrowIconRect.x = viewRect.x + menuItemGap;
  556. }
  557. }
  558. // Align the accelertor text and the check and arrow icons vertically
  559. // with the center of the label rect.
  560. acceleratorRect.y = labelRect.y + (labelRect.height2) - (acceleratorRect.height2);
  561. if( useCheckAndArrow() ) {
  562. arrowIconRect.y = labelRect.y + (labelRect.height2) - (arrowIconRect.height2);
  563. checkIconRect.y = labelRect.y + (labelRect.height2) - (checkIconRect.height2);
  564. }
  565. /*
  566. System.out.println("Layout: text="+menuItem.getText()+"\n\tv="
  567. +viewRect+"\n\tc="+checkIconRect+"\n\ti="
  568. +iconRect+"\n\tt="+textRect+"\n\tacc="
  569. +acceleratorRect+"\n\ta="+arrowIconRect+"\n");
  570. */
  571. return text;
  572. }
  573. /*
  574. * Returns false if the component is a JMenu and it is a top
  575. * level menu (on the menubar).
  576. */
  577. private boolean useCheckAndArrow(){
  578. boolean b = true;
  579. if((menuItem instanceof JMenu) &&
  580. (((JMenu)menuItem).isTopLevelMenu())) {
  581. b = false;
  582. }
  583. return b;
  584. }
  585. public MenuElement[] getPath() {
  586. MenuSelectionManager m = MenuSelectionManager.defaultManager();
  587. MenuElement oldPath[] = m.getSelectedPath();
  588. MenuElement newPath[];
  589. int i = oldPath.length;
  590. if (i == 0)
  591. return new MenuElement[0];
  592. Component parent = menuItem.getParent();
  593. if (oldPath[i-1].getComponent() == parent) {
  594. // The parent popup menu is the last so far
  595. newPath = new MenuElement[i+1];
  596. System.arraycopy(oldPath, 0, newPath, 0, i);
  597. newPath[i] = menuItem;
  598. } else {
  599. // A sibling menuitem is the current selection
  600. //
  601. // This probably needs to handle 'exit submenu into
  602. // a menu item. Search backwards along the current
  603. // selection until you find the parent popup menu,
  604. // then copy up to that and add yourself...
  605. int j;
  606. for (j = oldPath.length-1; j >= 0; j--) {
  607. if (oldPath[j].getComponent() == parent)
  608. break;
  609. }
  610. newPath = new MenuElement[j+2];
  611. System.arraycopy(oldPath, 0, newPath, 0, j+1);
  612. newPath[j+1] = menuItem;
  613. /*
  614. System.out.println("Sibling condition -- ");
  615. System.out.println("Old array : ");
  616. printMenuElementArray(oldPath, false);
  617. System.out.println("New array : ");
  618. printMenuElementArray(newPath, false);
  619. */
  620. }
  621. return newPath;
  622. }
  623. void printMenuElementArray(MenuElement path[], boolean dumpStack) {
  624. System.out.println("Path is(");
  625. int i, j;
  626. for(i=0,j=path.length; i<j ;i++){
  627. for (int k=0; k<=i; k++)
  628. System.out.print(" ");
  629. MenuElement me = (MenuElement) path[i];
  630. if(me instanceof JMenuItem)
  631. System.out.println(((JMenuItem)me).getText() + ", ");
  632. else if (me == null)
  633. System.out.println("NULL , ");
  634. else
  635. System.out.println("" + me + ", ");
  636. }
  637. System.out.println(")");
  638. if (dumpStack == true)
  639. Thread.dumpStack();
  640. }
  641. protected class MouseInputHandler implements MouseInputListener {
  642. public void mouseClicked(MouseEvent e) {}
  643. public void mousePressed(MouseEvent e) {
  644. }
  645. public void mouseReleased(MouseEvent e) {
  646. MenuSelectionManager manager =
  647. MenuSelectionManager.defaultManager();
  648. Point p = e.getPoint();
  649. if(p.x >= 0 && p.x < menuItem.getWidth() &&
  650. p.y >= 0 && p.y < menuItem.getHeight()) {
  651. manager.clearSelectedPath();
  652. menuItem.doClick(0);
  653. } else {
  654. manager.processMouseEvent(e);
  655. }
  656. }
  657. public void mouseEntered(MouseEvent e) {
  658. // System.out.println("menu item entered: " + menuItem.getText());
  659. MenuSelectionManager manager = MenuSelectionManager.defaultManager();
  660. int modifiers = e.getModifiers();
  661. // 4188027: drag enter/exit added in JDK 1.1.7A, JDK1.2
  662. if ((modifiers & (InputEvent.BUTTON1_MASK |
  663. InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK)) !=0 ) {
  664. MenuSelectionManager.defaultManager().processMouseEvent(e);
  665. } else {
  666. manager.setSelectedPath(getPath());
  667. }
  668. }
  669. public void mouseExited(MouseEvent e) {
  670. MenuSelectionManager manager = MenuSelectionManager.defaultManager();
  671. int modifiers = e.getModifiers();
  672. // 4188027: drag enter/exit added in JDK 1.1.7A, JDK1.2
  673. if ((modifiers & (InputEvent.BUTTON1_MASK |
  674. InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK)) !=0 ) {
  675. MenuSelectionManager.defaultManager().processMouseEvent(e);
  676. } else {
  677. MenuElement path[] = manager.getSelectedPath();
  678. if (path.length > 1) {
  679. MenuElement newPath[] = new MenuElement[path.length-1];
  680. int i,c;
  681. for(i=0,c=path.length-1;i<c;i++)
  682. newPath[i] = path[i];
  683. manager.setSelectedPath(newPath);
  684. }
  685. }
  686. }
  687. public void mouseDragged(MouseEvent e) {
  688. MenuSelectionManager.defaultManager().processMouseEvent(e);
  689. }
  690. public void mouseMoved(MouseEvent e) {
  691. }
  692. }
  693. private class MenuDragMouseHandler implements MenuDragMouseListener {
  694. public void menuDragMouseEntered(MenuDragMouseEvent e) {}
  695. public void menuDragMouseDragged(MenuDragMouseEvent e) {
  696. MenuSelectionManager manager = e.getMenuSelectionManager();
  697. MenuElement path[] = e.getPath();
  698. manager.setSelectedPath(path);
  699. }
  700. public void menuDragMouseExited(MenuDragMouseEvent e) {}
  701. public void menuDragMouseReleased(MenuDragMouseEvent e) {
  702. MenuSelectionManager manager = e.getMenuSelectionManager();
  703. MenuElement path[] = e.getPath();
  704. Point p = e.getPoint();
  705. if(p.x >= 0 && p.x < menuItem.getWidth() &&
  706. p.y >= 0 && p.y < menuItem.getHeight()) {
  707. manager.clearSelectedPath();
  708. menuItem.doClick(0);
  709. } else {
  710. manager.clearSelectedPath();
  711. }
  712. }
  713. }
  714. private class MenuKeyHandler implements MenuKeyListener {
  715. public void menuKeyTyped(MenuKeyEvent e) {
  716. int key = menuItem.getMnemonic();
  717. if(key == 0)
  718. return;
  719. if(lower(key) == lower((int)(e.getKeyChar()))) {
  720. MenuSelectionManager manager =
  721. e.getMenuSelectionManager();
  722. manager.clearSelectedPath();
  723. menuItem.doClick(0);
  724. e.consume();
  725. }
  726. }
  727. public void menuKeyPressed(MenuKeyEvent e) {}
  728. public void menuKeyReleased(MenuKeyEvent e) {}
  729. private int lower(int ascii) {
  730. if(ascii >= 'A' && ascii <= 'Z')
  731. return ascii + 'a' - 'A';
  732. else
  733. return ascii;
  734. }
  735. }
  736. private class PropertyChangeHandler implements PropertyChangeListener {
  737. public void propertyChange(PropertyChangeEvent e) {
  738. String name = e.getPropertyName();
  739. // System.out.println("Change prop " + name + " on " + menuItem.getText());
  740. if (e.getPropertyName().equals("labelFor") ||
  741. e.getPropertyName().equals("displayedMnemonic")) {
  742. installKeyboardActions();
  743. } else if (name.equals("text")) {
  744. // remove the old html view client property if one
  745. // existed, and install a new one if the text installed
  746. // into the JLabel is html source.
  747. JMenuItem lbl = ((JMenuItem) e.getSource());
  748. String text = lbl.getText();
  749. BasicHTML.updateRenderer(lbl, text);
  750. }
  751. }
  752. }
  753. }