001: /*
002: * @(#)VsnetMenuUI.java
003: *
004: * Copyright 2002 JIDE Software Inc. All rights reserved.
005: */
006:
007: package com.jidesoft.plaf.vsnet;
008:
009: import com.jidesoft.plaf.UIDefaultsLookup;
010: import com.jidesoft.plaf.basic.ThemePainter;
011: import com.jidesoft.swing.ButtonStyle;
012: import com.jidesoft.swing.JideSwingUtilities;
013: import com.jidesoft.swing.TopLevelMenuContainer;
014: import com.sun.java.swing.plaf.windows.WindowsGraphicsUtils;
015: import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;
016:
017: import javax.swing.*;
018: import javax.swing.border.Border;
019: import javax.swing.event.*;
020: import javax.swing.plaf.ComponentUI;
021: import java.awt.*;
022: import java.awt.event.ActionEvent;
023: import java.awt.event.KeyEvent;
024: import java.awt.event.MouseEvent;
025: import java.awt.event.MouseMotionListener;
026: import java.beans.PropertyChangeEvent;
027: import java.beans.PropertyChangeListener;
028: import java.util.ArrayList;
029: import java.util.Arrays;
030:
031: /**
032: * Menu UI implementation
033: */
034: public class VsnetMenuUI extends VsnetMenuItemUI {
035: protected ChangeListener changeListener;
036: protected PropertyChangeListener propertyChangeListener;
037: protected MenuListener menuListener;
038:
039: private int lastMnemonic = 0;
040:
041: private static final boolean DEBUG = false; // show bad params, misc.
042:
043: private static boolean crossMenuMnemonic = true;
044:
045: private boolean isMouseOver = false;
046: private PopupMenuListener popupMenuListener;
047:
048: public static ComponentUI createUI(JComponent x) {
049: return new VsnetMenuUI();
050: }
051:
052: @Override
053: protected void installDefaults() {
054: super .installDefaults();
055: if (menuItem instanceof JMenu) {
056: ((JMenu) menuItem).setDelay(200);
057: }
058: crossMenuMnemonic = UIDefaultsLookup
059: .getBoolean("Menu.crossMenuMnemonic");
060: }
061:
062: @Override
063: protected String getPropertyPrefix() {
064: return "Menu";
065: }
066:
067: @Override
068: protected void paintBackground(Graphics g, JMenuItem menuItem,
069: Color bgColor) {
070: if (!(menuItem instanceof JMenu)
071: || !((JMenu) menuItem).isTopLevelMenu()) {
072: super .paintBackground(g, menuItem, bgColor);
073: return;
074: }
075:
076: ButtonModel model = menuItem.getModel();
077: Color oldColor = g.getColor();
078: int menuWidth = 0;
079: int menuHeight = 0;
080: if (JideSwingUtilities.getOrientationOf(menuItem) == SwingConstants.HORIZONTAL) {
081: menuWidth = menuItem.getWidth();
082: menuHeight = menuItem.getHeight();
083: } else {
084: menuWidth = menuItem.getHeight();
085: menuHeight = menuItem.getWidth();
086: }
087:
088: UIDefaults table = UIManager.getLookAndFeelDefaults();
089: Color borderColor = getPainter().getMenuItemBorderColor();
090: Color mouseHoverBackground = table
091: .getColor("Menu.mouseHoverBackground");
092: Border mouseHoverBorder = table
093: .getBorder("Menu.mouseHoverBorder");
094:
095: if (menuItem.isOpaque()) {
096: if (menuItem.getParent() != null) {
097: g.setColor(menuItem.getParent().getBackground());
098: } else {
099: g.setColor(menuItem.getBackground());
100: }
101: g.fillRect(0, 0, menuWidth, menuHeight);
102: }
103:
104: Rectangle rect = new Rectangle(0, 0, menuWidth, menuHeight);
105: if (menuItem instanceof JMenu && model.isSelected()) {
106: // Draw a dark shadow border without bottom
107: // TODO: we should consider the location of popup menu and decide which side not paint.
108: // TODO: for example if the menu is going upward, we shouldn't paint the top.
109: if (((JMenu) menuItem).getPopupMenu().isVisible()) { // paint differently if popup menu is visible
110: if (JideSwingUtilities.getOrientationOf(menuItem) == SwingConstants.HORIZONTAL) {
111: getPainter().paintMenuItemBackground(
112: menuItem,
113: g,
114: rect,
115: JideSwingUtilities
116: .getOrientationOf(menuItem),
117: ThemePainter.STATE_DEFAULT, false);
118: g.setColor(borderColor);
119: g.drawLine(0, 0, menuWidth - 1, 0);
120: g.drawLine(menuWidth - 1, 0, menuWidth - 1,
121: menuHeight);
122: g.drawLine(0, menuHeight, 0, 1);
123: } else {
124: getPainter().paintMenuItemBackground(
125: menuItem,
126: g,
127: rect,
128: JideSwingUtilities
129: .getOrientationOf(menuItem),
130: ThemePainter.STATE_DEFAULT, false);
131: g.setColor(borderColor);
132: g.drawLine(0, menuHeight - 1, menuWidth - 1,
133: menuHeight - 1);
134: g.drawLine(menuWidth - 1, 0, menuWidth - 1,
135: menuHeight);
136: g.drawLine(0, menuHeight, 0, 1);
137: }
138: } else {
139: getPainter().paintMenuItemBackground(menuItem, g, rect,
140: JideSwingUtilities.getOrientationOf(menuItem),
141: ThemePainter.STATE_ROLLOVER);
142: }
143: } else if (isMouseOver() && model.isEnabled()) {
144: getPainter().paintMenuItemBackground(menuItem, g, rect,
145: JideSwingUtilities.getOrientationOf(menuItem),
146: ThemePainter.STATE_ROLLOVER);
147: }
148:
149: if (isDownArrowVisible(menuItem.getParent())) {
150: g.setColor(menuItem.isEnabled() ? Color.BLACK : Color.GRAY);
151: int middle = menuWidth - 9;
152: g.drawLine(middle - 2, menuHeight / 2 - 1, middle + 2,
153: menuHeight / 2 - 1);
154: g.drawLine(middle - 1, menuHeight / 2, middle + 1,
155: menuHeight / 2);
156: g.drawLine(middle, menuHeight / 2 + 1, middle,
157: menuHeight / 2 + 1);
158: }
159: g.setColor(oldColor);
160: }
161:
162: @Override
163: protected void installListeners() {
164: super .installListeners();
165:
166: if (changeListener == null)
167: changeListener = createChangeListener(menuItem);
168:
169: if (changeListener != null)
170: menuItem.addChangeListener(changeListener);
171:
172: if (propertyChangeListener == null)
173: propertyChangeListener = createPropertyChangeListener(menuItem);
174:
175: if (propertyChangeListener != null)
176: menuItem.addPropertyChangeListener(propertyChangeListener);
177:
178: if (menuListener == null)
179: menuListener = createMenuListener(menuItem);
180:
181: if (menuListener != null && menuItem instanceof JMenu) {
182: ((JMenu) menuItem).addMenuListener(menuListener);
183: }
184:
185: if (popupMenuListener == null) {
186: popupMenuListener = createPopupMenuListener();
187: }
188: if (popupMenuListener != null && menuItem instanceof JMenu) {
189: ((JMenu) menuItem).getPopupMenu().addPopupMenuListener(
190: popupMenuListener);
191: }
192: }
193:
194: protected PopupMenuListener createPopupMenuListener() {
195: return new PopupMenuListener() {
196: public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
197: repaint();
198: }
199:
200: public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
201: repaint();
202: }
203:
204: public void popupMenuCanceled(PopupMenuEvent e) {
205: repaint();
206: }
207:
208: private void repaint() {
209: if (menuItem != null) {
210: menuItem.repaint();
211: }
212: }
213:
214: };
215: }
216:
217: @Override
218: protected void installKeyboardActions() {
219: super .installKeyboardActions();
220: updateMnemonicBinding();
221: }
222:
223: void updateMnemonicBinding() {
224: int mnemonic = menuItem.getModel().getMnemonic();
225: int[] shortcutKeys = (int[]) UIDefaultsLookup
226: .get("Menu.shortcutKeys");
227: if (shortcutKeys == null) {
228: shortcutKeys = new int[] { KeyEvent.ALT_MASK };
229: }
230: if (mnemonic == lastMnemonic || shortcutKeys == null) {
231: return;
232: }
233: if (lastMnemonic != 0 && windowInputMap != null) {
234: for (int i = 0; i < shortcutKeys.length; i++) {
235: windowInputMap.remove(KeyStroke.getKeyStroke(
236: lastMnemonic, shortcutKeys[i], false));
237: }
238: }
239: if (mnemonic != 0) {
240: if (windowInputMap == null) {
241: windowInputMap = createInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
242: SwingUtilities.replaceUIInputMap(menuItem,
243: JComponent.WHEN_IN_FOCUSED_WINDOW,
244: windowInputMap);
245: }
246: for (int i = 0; i < shortcutKeys.length; i++) {
247: windowInputMap.put(KeyStroke.getKeyStroke(mnemonic,
248: shortcutKeys[i], false), "selectMenu");
249: }
250: }
251: lastMnemonic = mnemonic;
252: }
253:
254: @Override
255: protected void uninstallKeyboardActions() {
256: super .uninstallKeyboardActions();
257: }
258:
259: /**
260: * The ActionMap for BasicMenUI can not be shared, this is subclassed
261: * to create a new one for each invocation.
262: */
263: @Override
264: ActionMap getActionMap() {
265: return createActionMap();
266: }
267:
268: /**
269: * Invoked to create the ActionMap.
270: */
271: @Override
272: protected ActionMap createActionMap() {
273: ActionMap am = super .createActionMap();
274: if (am != null && menuItem instanceof JMenu) {
275: am
276: .put("selectMenu", new PostAction((JMenu) menuItem,
277: true));
278: }
279: return am;
280: }
281:
282: @Override
283: protected MouseInputListener createMouseInputListener(JComponent c) {
284: return new MouseInputHandler();
285: }
286:
287: protected MenuListener createMenuListener(JComponent c) {
288: return new MenuHandler();
289: }
290:
291: protected ChangeListener createChangeListener(JComponent c) {
292: return null;
293: }
294:
295: protected PropertyChangeListener createPropertyChangeListener(
296: JComponent c) {
297: return new PropertyChangeHandler();
298: }
299:
300: @Override
301: protected void uninstallDefaults() {
302: menuItem.setArmed(false);
303: menuItem.setSelected(false);
304: menuItem.resetKeyboardActions();
305: super .uninstallDefaults();
306: }
307:
308: @Override
309: protected void uninstallListeners() {
310: super .uninstallListeners();
311:
312: if (changeListener != null)
313: menuItem.removeChangeListener(changeListener);
314:
315: changeListener = null;
316:
317: if (propertyChangeListener != null)
318: menuItem
319: .removePropertyChangeListener(propertyChangeListener);
320:
321: propertyChangeListener = null;
322:
323: if (menuListener != null && menuItem instanceof JMenu) {
324: ((JMenu) menuItem).removeMenuListener(menuListener);
325: }
326:
327: menuListener = null;
328:
329: if (popupMenuListener != null && menuItem instanceof JMenu) {
330: ((JMenu) menuItem).getPopupMenu().removePopupMenuListener(
331: popupMenuListener);
332: }
333:
334: popupMenuListener = null;
335: }
336:
337: @Override
338: protected MenuDragMouseListener createMenuDragMouseListener(
339: JComponent c) {
340: return new MenuDragMouseHandler();
341: }
342:
343: @Override
344: protected MenuKeyListener createMenuKeyListener(JComponent c) {
345: return new MenuKeyHandler();
346: }
347:
348: @Override
349: public Dimension getMaximumSize(JComponent c) {
350: if (menuItem instanceof JMenu
351: && ((JMenu) menuItem).isTopLevelMenu()) {
352: Dimension d = c.getPreferredSize();
353: if (JideSwingUtilities.getOrientationOf(menuItem) == SwingConstants.HORIZONTAL) {
354: return new Dimension(d.width, Short.MAX_VALUE);
355: } else {
356: return new Dimension(Short.MAX_VALUE, d.height);
357: }
358: }
359: return null;
360: }
361:
362: protected static void setupPostTimer(JMenu menu) {
363: Timer timer = new Timer(menu.getDelay(), new PostAction(menu,
364: false));
365: timer.setRepeats(false);
366: timer.start();
367: }
368:
369: protected static void appendPath(MenuElement[] path,
370: MenuElement elem) {
371: MenuElement newPath[] = new MenuElement[path.length + 1];
372: System.arraycopy(path, 0, newPath, 0, path.length);
373: newPath[path.length] = elem;
374: MenuSelectionManager.defaultManager().setSelectedPath(newPath);
375: }
376:
377: protected static class PostAction extends AbstractAction {
378: JMenu menu;
379: boolean force = false;
380:
381: PostAction(JMenu menu, boolean shouldForce) {
382: this .menu = menu;
383: this .force = shouldForce;
384: }
385:
386: public void actionPerformed(ActionEvent e) {
387: if (!crossMenuMnemonic) {
388: JPopupMenu pm = getActivePopupMenu();
389: if (pm != null && pm != menu.getParent()) {
390: return;
391: }
392: }
393:
394: final MenuSelectionManager defaultManager = MenuSelectionManager
395: .defaultManager();
396: if (force) {
397: Container cnt = menu.getParent();
398: if (cnt != null && cnt instanceof JMenuBar) {
399: MenuElement me[];
400: MenuElement subElements[];
401:
402: subElements = menu.getPopupMenu().getSubElements();
403: if (subElements.length > 0) {
404: me = new MenuElement[4];
405: me[0] = (MenuElement) cnt;
406: me[1] = menu;
407: me[2] = menu.getPopupMenu();
408: me[3] = subElements[0];
409: } else {
410: me = new MenuElement[3];
411: me[0] = (MenuElement) cnt;
412: me[1] = menu;
413: me[2] = menu.getPopupMenu();
414: }
415: defaultManager.setSelectedPath(me);
416: }
417: } else {
418: MenuElement path[] = defaultManager.getSelectedPath();
419: if (path.length > 0 && path[path.length - 1] == menu) {
420: appendPath(path, menu.getPopupMenu());
421: }
422: }
423: }
424:
425: @Override
426: public boolean isEnabled() {
427: return menu.getModel().isEnabled();
428: }
429: }
430:
431: private class PropertyChangeHandler implements
432: PropertyChangeListener {
433: public void propertyChange(PropertyChangeEvent e) {
434: String prop = e.getPropertyName();
435: if (prop.equals(AbstractButton.MNEMONIC_CHANGED_PROPERTY)) {
436: updateMnemonicBinding();
437: } else if (prop.equals(ButtonStyle.BUTTON_STYLE_PROPERTY)) {
438: AbstractButton b = (AbstractButton) e.getSource();
439: b.repaint();
440: } else if ("verticalTextPosition".equals(prop)
441: || "horizontalTextPosition".equals(prop)) {
442: AbstractButton b = (AbstractButton) e.getSource();
443: b.updateUI();
444: }
445: }
446: }
447:
448: /**
449: * Instantiated and used by a menu item to handle the current menu selection
450: * from mouse events. A MouseInputHandler processes and forwards all mouse events
451: * to a shared instance of the MenuSelectionManager.
452: * <p/>
453: * This class is protected so that it can be subclassed by other look and
454: * feels to implement their own mouse handling behavior. All overridden
455: * methods should call the parent methods so that the menu selection
456: * is correct.
457: *
458: * @see MenuSelectionManager
459: * @since 1.4
460: */
461: protected class MouseInputHandler implements MouseInputListener {
462:
463: public void mouseClicked(MouseEvent e) {
464: }
465:
466: /**
467: * Invoked when the mouse has been clicked on the menu. This
468: * method clears or sets the selection path of the
469: * MenuSelectionManager.
470: *
471: * @param e the mouse event
472: */
473: public void mousePressed(MouseEvent e) {
474: if (!SwingUtilities.isLeftMouseButton(e)) {
475: return;
476: }
477:
478: if (!(menuItem instanceof JMenu)) {
479: return;
480: }
481:
482: JMenu menu = (JMenu) menuItem;
483: if (!menu.isEnabled())
484: return;
485:
486: MenuSelectionManager manager = MenuSelectionManager
487: .defaultManager();
488: if (menu.getParent() instanceof JMenuBar
489: || menu.getParent() instanceof TopLevelMenuContainer) {
490: if (menu.isSelected()) {
491: manager.clearSelectedPath();
492: } else {
493: Container cnt = menu.getParent();
494: if (cnt != null
495: && cnt.getParent() instanceof MenuElement) {
496: MenuElement me[] = new MenuElement[3];
497: me[0] = (MenuElement) cnt.getParent();
498: me[1] = ((MenuElement) cnt);
499: me[2] = menu;
500: manager.setSelectedPath(me);
501: } else if (cnt != null
502: && cnt instanceof MenuElement) {
503: MenuElement me[] = new MenuElement[2];
504: me[0] = (MenuElement) cnt;
505: me[1] = menu;
506: manager.setSelectedPath(me);
507: }
508: }
509: }
510:
511: MenuElement selectedPath[] = manager.getSelectedPath();
512: if (selectedPath.length > 0
513: && selectedPath[selectedPath.length - 1] != menu
514: .getPopupMenu()) {
515:
516: if (menu.isTopLevelMenu() || menu.getDelay() == 0) {
517: appendPath(selectedPath, menu.getPopupMenu());
518: } else {
519: setupPostTimer(menu);
520: }
521: }
522: }
523:
524: /**
525: * Invoked when the mouse has been released on the menu. Delegates the
526: * mouse event to the MenuSelectionManager.
527: *
528: * @param e the mouse event
529: */
530: public void mouseReleased(MouseEvent e) {
531: if (!SwingUtilities.isLeftMouseButton(e)) {
532: return;
533: }
534:
535: if (!(menuItem instanceof JMenu)) {
536: return;
537: }
538:
539: JMenu menu = (JMenu) menuItem;
540: if (!menu.isEnabled())
541: return;
542: MenuSelectionManager manager = MenuSelectionManager
543: .defaultManager();
544: manager.processMouseEvent(e);
545: if (!e.isConsumed())
546: manager.clearSelectedPath();
547: }
548:
549: /**
550: * Invoked when the cursor enters the menu. This method sets the selected
551: * path for the MenuSelectionManager and handles the case
552: * in which a menu item is used to pop up an additional menu, as in a
553: * hierarchical menu system.
554: *
555: * @param e the mouse event; not used
556: */
557: public void mouseEntered(MouseEvent e) {
558: if (!(menuItem instanceof JMenu)) {
559: return;
560: }
561: JMenu menu = (JMenu) menuItem;
562: if (!menu.isEnabled())
563: return;
564:
565: MenuSelectionManager manager = MenuSelectionManager
566: .defaultManager();
567: MenuElement selectedPath[] = manager.getSelectedPath();
568: if (!menu.isTopLevelMenu()) {
569: if (!(selectedPath.length > 0 && selectedPath[selectedPath.length - 1] == menu
570: .getPopupMenu())) {
571: if (menu.getDelay() == 0) {
572: appendPath(getPath(), menu.getPopupMenu());
573: } else {
574: manager.setSelectedPath(getPath());
575: setupPostTimer(menu);
576: }
577: }
578: } else {
579: if (selectedPath.length > 0
580: && selectedPath[0] == menu.getParent()) {
581: MenuElement newPath[] = new MenuElement[3];
582: // A top level menu's parent is by definition
583: // a JMenuBar
584: newPath[0] = (MenuElement) menu.getParent();
585: newPath[1] = menu;
586: newPath[2] = menu.getPopupMenu();
587: manager.setSelectedPath(newPath);
588: }
589: }
590:
591: if (!SwingUtilities.isLeftMouseButton(e)) {
592: setMouseOver(true);
593: }
594: menuItem.repaint();
595: }
596:
597: public void mouseExited(MouseEvent e) {
598: setMouseOver(false);
599: menuItem.repaint();
600: }
601:
602: /**
603: * Invoked when a mouse button is pressed on the menu and then dragged.
604: * Delegates the mouse event to the MenuSelectionManager.
605: *
606: * @param e the mouse event
607: * @see MouseMotionListener#mouseDragged
608: */
609: public void mouseDragged(MouseEvent e) {
610: if (!(menuItem instanceof JMenu)) {
611: return;
612: }
613: JMenu menu = (JMenu) menuItem;
614: if (!menu.isEnabled())
615: return;
616: MenuSelectionManager.defaultManager().processMouseEvent(e);
617: }
618:
619: public void mouseMoved(MouseEvent e) {
620: }
621: }
622:
623: private class MenuHandler implements MenuListener {
624: public void menuSelected(MenuEvent e) {
625: }
626:
627: public void menuDeselected(MenuEvent e) {
628: }
629:
630: public void menuCanceled(MenuEvent e) {
631: if (!(menuItem instanceof JMenu)) {
632: return;
633: }
634: JMenu m = (JMenu) e.getSource();
635: MenuSelectionManager manager = MenuSelectionManager
636: .defaultManager();
637: if (manager.isComponentPartOfCurrentMenu(m))
638: MenuSelectionManager.defaultManager()
639: .clearSelectedPath();
640: }
641:
642: }
643:
644: private class MenuDragMouseHandler implements MenuDragMouseListener {
645: public void menuDragMouseEntered(MenuDragMouseEvent e) {
646: }
647:
648: public void menuDragMouseDragged(MenuDragMouseEvent e) {
649: if (!(menuItem instanceof JMenu)) {
650: return;
651: }
652: if (menuItem.isEnabled() == false)
653: return;
654:
655: MenuSelectionManager manager = e.getMenuSelectionManager();
656: MenuElement path[] = e.getPath();
657:
658: Point p = e.getPoint();
659: if (p.x >= 0 && p.x < menuItem.getWidth() && p.y >= 0
660: && p.y < menuItem.getHeight()) {
661: JMenu menu = (JMenu) menuItem;
662: MenuElement selectedPath[] = manager.getSelectedPath();
663: if (!(selectedPath.length > 0 && selectedPath[selectedPath.length - 1] == menu
664: .getPopupMenu())) {
665: if (menu.isTopLevelMenu() || menu.getDelay() == 0
666: || e.getID() == MouseEvent.MOUSE_DRAGGED) {
667: appendPath(path, menu.getPopupMenu());
668: } else {
669: manager.setSelectedPath(path);
670: setupPostTimer(menu);
671: }
672: }
673: } else if (e.getID() == MouseEvent.MOUSE_RELEASED) {
674: Component comp = manager.componentForPoint(e
675: .getComponent(), e.getPoint());
676: if (comp == null)
677: manager.clearSelectedPath();
678: }
679:
680: }
681:
682: public void menuDragMouseExited(MenuDragMouseEvent e) {
683: }
684:
685: public void menuDragMouseReleased(MenuDragMouseEvent e) {
686: }
687: }
688:
689: static JPopupMenu getActivePopupMenu() {
690: MenuElement[] path = MenuSelectionManager.defaultManager()
691: .getSelectedPath();
692: for (int i = path.length - 1; i >= 0; i--) {
693: MenuElement elem = path[i];
694: if (elem instanceof JPopupMenu) {
695: return (JPopupMenu) elem;
696: }
697: }
698: return null;
699: }
700:
701: /**
702: * Handles the mnemonic handling for the JMenu and JMenuItems.
703: */
704: private class MenuKeyHandler implements MenuKeyListener {
705:
706: /**
707: * Opens the SubMenu
708: */
709: public void menuKeyTyped(MenuKeyEvent e) {
710: if (DEBUG) {
711: System.out.println("in BasicMenuUI.menuKeyTyped for "
712: + menuItem.getText());
713: }
714: if (!crossMenuMnemonic) {
715: JPopupMenu pm = getActivePopupMenu();
716: if (pm != null && pm != menuItem.getParent()) {
717: return;
718: }
719: }
720:
721: int key = menuItem.getMnemonic();
722: if (key == 0)
723: return;
724: MenuElement path[] = e.getPath();
725: if (lower((char) key) == lower(e.getKeyChar())) {
726: JPopupMenu popupMenu = ((JMenu) menuItem)
727: .getPopupMenu();
728: ArrayList newList = new ArrayList(Arrays.asList(path));
729: newList.add(popupMenu);
730: MenuElement sub[] = popupMenu.getSubElements();
731: if (sub.length > 0) {
732: newList.add(sub[0]);
733: }
734: MenuSelectionManager manager = e
735: .getMenuSelectionManager();
736: MenuElement newPath[] = new MenuElement[0];
737: newPath = (MenuElement[]) newList.toArray(newPath);
738: manager.setSelectedPath(newPath);
739: e.consume();
740: }
741: }
742:
743: /**
744: * Handles the mnemonics for the menu items. Will also handle duplicate mnemonics.
745: * Perhaps this should be moved into BasicPopupMenuUI. See 4670831
746: */
747: public void menuKeyPressed(MenuKeyEvent e) {
748: if (DEBUG) {
749: System.out.println("in BasicMenuUI.menuKeyPressed for "
750: + menuItem.getText());
751: }
752: // Handle the case for Escape or Enter...
753: char keyChar = e.getKeyChar();
754: if (!Character.isLetterOrDigit(keyChar))
755: return;
756:
757: MenuSelectionManager manager = e.getMenuSelectionManager();
758: MenuElement path[] = e.getPath();
759: MenuElement selectedPath[] = manager.getSelectedPath();
760:
761: for (int i = selectedPath.length - 1; i >= 0; i--) {
762: if (selectedPath[i] == menuItem) {
763: JPopupMenu popupMenu = ((JMenu) menuItem)
764: .getPopupMenu();
765: if (!popupMenu.isVisible()) {
766: return; // Do not invoke items from invisible popup
767: }
768: MenuElement items[] = popupMenu.getSubElements();
769:
770: MenuElement currentItem = selectedPath[selectedPath.length - 1];
771: int currentIndex = -1;
772: int matches = 0;
773: int firstMatch = -1;
774: int indexes[] = null;
775:
776: for (int j = 0; j < items.length; j++) {
777: if (!(items[j] instanceof JMenuItem)) {
778: continue;
779: }
780: int key = ((JMenuItem) items[j]).getMnemonic();
781: if (lower((char) key) == lower(keyChar)) {
782: if (matches == 0) {
783: firstMatch = j;
784: matches++;
785: } else {
786: if (indexes == null) {
787: indexes = new int[items.length];
788: indexes[0] = firstMatch;
789: }
790: indexes[matches++] = j;
791: }
792: }
793: if (currentItem == items[j]) {
794: currentIndex = matches - 1;
795: }
796: }
797:
798: if (matches == 0) {
799: ; // no op (consume)
800: } else if (matches == 1) {
801: // Invoke the menu action
802: JMenuItem item = (JMenuItem) items[firstMatch];
803: if (!(item instanceof JMenu)) {
804: // Let Submenus be handled by menuKeyTyped
805: manager.clearSelectedPath();
806: item.doClick();
807: }
808: } else {
809: // Select the menu item with the matching mnemonic. If
810: // the same mnemonic has been invoked then select the next
811: // menu item in the cycle.
812: MenuElement newItem = null;
813:
814: newItem = items[indexes[(currentIndex + 1)
815: % matches]];
816:
817: MenuElement newPath[] = new MenuElement[path.length + 2];
818: System.arraycopy(path, 0, newPath, 0,
819: path.length);
820: newPath[path.length] = popupMenu;
821: newPath[path.length + 1] = newItem;
822: manager.setSelectedPath(newPath);
823: }
824: e.consume();
825: return;
826: }
827: }
828: }
829:
830: public void menuKeyReleased(MenuKeyEvent e) {
831: }
832:
833: private char lower(char keyChar) {
834: return Character.toLowerCase(keyChar);
835: }
836: }
837:
838: /**
839: * Method which renders the text of the current menu item.
840: * <p/>
841: *
842: * @param g Graphics context
843: * @param menuItem Current menu item to render
844: * @param textRect Bounding rectangle to render the text.
845: * @param text String to render
846: * @since 1.4
847: */
848: @Override
849: protected void paintText(Graphics g, JMenuItem menuItem,
850: Rectangle textRect, String text) {
851: // Note: This method is almost identical to the same method in WindowsMenuItemUI
852: ButtonModel model = menuItem.getModel();
853:
854: if (!(menuItem instanceof JMenu)
855: || !((JMenu) menuItem).isTopLevelMenu()) {
856: if (menuItem.getComponentOrientation().isLeftToRight()) {
857: int defaultTextIconGap = UIDefaultsLookup
858: .getInt("MenuItem.textIconGap");
859: int defaultShadowWidth = UIDefaultsLookup
860: .getInt("MenuItem.shadowWidth");
861: textRect.x = defaultShadowWidth + defaultTextIconGap;
862: } else {
863: // isLeftToRight is false
864: }
865: }
866:
867: if (!model.isEnabled()) {
868: // *** paint the text disabled
869: textRect.y++;
870: WindowsGraphicsUtils.paintText(g, menuItem, textRect, text,
871: 0);
872: } else {
873: FontMetrics fm = g.getFontMetrics();
874: int mnemonicIndex = menuItem.getDisplayedMnemonicIndex();
875: // W2K Feature: Check to see if the Underscore should be rendered.
876: if (WindowsLookAndFeel.isMnemonicHidden()) {
877: mnemonicIndex = -1;
878: }
879:
880: Color oldColor = g.getColor();
881:
882: // For Win95, the selected text color is the selection forground color
883: if (model.isSelected()) {
884: if (/*SystemInfo.isClassicWindows() ||
885: */!((JMenu) menuItem).isTopLevelMenu()) {
886:
887: g.setColor(selectionForeground); // Uses protected field.
888: }
889: }
890: JideSwingUtilities.drawStringUnderlineCharAt(menuItem, g,
891: text, mnemonicIndex, textRect.x, textRect.y
892: + fm.getAscent());
893: g.setColor(oldColor);
894: }
895: // }
896: }
897:
898: /**
899: * Set the temporary flag to indicate if the mouse has entered the menu.
900: */
901: protected void setMouseOver(boolean over) {
902: isMouseOver = over;
903: menuItem.getModel().setRollover(isMouseOver);
904: }
905:
906: /**
907: * Get the temporary flag to indicate if the mouse has entered the menu.
908: */
909: protected boolean isMouseOver() {
910: return isMouseOver;
911: }
912:
913: @Override
914: public Dimension getPreferredSize(JComponent c) {
915: Dimension size = super .getPreferredSize(c);
916: if (menuItem instanceof JMenu
917: && ((JMenu) menuItem).isTopLevelMenu()
918: && isDownArrowVisible(menuItem.getParent())) {
919: if (JideSwingUtilities.getOrientationOf(menuItem) == SwingConstants.HORIZONTAL)
920: size.width += 11;
921: else
922: size.height += 11;
923: }
924: return size;
925: }
926: }
|