Source for javax.swing.plaf.basic.BasicMenuItemUI

   1: /* BasicMenuItemUI.java --
   2:    Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10:  
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.plaf.basic;
  40: 
  41: import gnu.classpath.SystemProperties;
  42: 
  43: import java.awt.Color;
  44: import java.awt.Component;
  45: import java.awt.Container;
  46: import java.awt.Dimension;
  47: import java.awt.Font;
  48: import java.awt.FontMetrics;
  49: import java.awt.Graphics;
  50: import java.awt.Insets;
  51: import java.awt.Rectangle;
  52: import java.awt.event.ActionEvent;
  53: import java.awt.event.ItemEvent;
  54: import java.awt.event.ItemListener;
  55: import java.awt.event.KeyEvent;
  56: import java.awt.event.MouseEvent;
  57: import java.awt.font.FontRenderContext;
  58: import java.awt.font.TextLayout;
  59: import java.awt.geom.AffineTransform;
  60: import java.beans.PropertyChangeEvent;
  61: import java.beans.PropertyChangeListener;
  62: import java.util.ArrayList;
  63: 
  64: import javax.swing.AbstractAction;
  65: import javax.swing.AbstractButton;
  66: import javax.swing.ActionMap;
  67: import javax.swing.ButtonModel;
  68: import javax.swing.Icon;
  69: import javax.swing.InputMap;
  70: import javax.swing.JCheckBoxMenuItem;
  71: import javax.swing.JComponent;
  72: import javax.swing.JMenu;
  73: import javax.swing.JMenuItem;
  74: import javax.swing.JPopupMenu;
  75: import javax.swing.KeyStroke;
  76: import javax.swing.LookAndFeel;
  77: import javax.swing.MenuElement;
  78: import javax.swing.MenuSelectionManager;
  79: import javax.swing.SwingConstants;
  80: import javax.swing.SwingUtilities;
  81: import javax.swing.UIDefaults;
  82: import javax.swing.UIManager;
  83: import javax.swing.event.MenuDragMouseEvent;
  84: import javax.swing.event.MenuDragMouseListener;
  85: import javax.swing.event.MenuKeyEvent;
  86: import javax.swing.event.MenuKeyListener;
  87: import javax.swing.event.MouseInputListener;
  88: import javax.swing.plaf.ActionMapUIResource;
  89: import javax.swing.plaf.ComponentInputMapUIResource;
  90: import javax.swing.plaf.ComponentUI;
  91: import javax.swing.plaf.MenuItemUI;
  92: import javax.swing.text.View;
  93: 
  94: /**
  95:  * UI Delegate for JMenuItem.
  96:  */
  97: public class BasicMenuItemUI extends MenuItemUI
  98: {
  99:   /**
 100:    * Font to be used when displaying menu item's accelerator.
 101:    */
 102:   protected Font acceleratorFont;
 103: 
 104:   /**
 105:    * Color to be used when displaying menu item's accelerator.
 106:    */
 107:   protected Color acceleratorForeground;
 108: 
 109:   /**
 110:    * Color to be used when displaying menu item's accelerator when menu item is
 111:    * selected.
 112:    */
 113:   protected Color acceleratorSelectionForeground;
 114: 
 115:   /**
 116:    * Icon that is displayed after the text to indicated that this menu contains
 117:    * submenu.
 118:    */
 119:   protected Icon arrowIcon;
 120: 
 121:   /**
 122:    * Icon that is displayed before the text. This icon is only used in
 123:    * JCheckBoxMenuItem or JRadioBoxMenuItem.
 124:    */
 125:   protected Icon checkIcon;
 126: 
 127:   /**
 128:    * Number of spaces between icon and text.
 129:    */
 130:   protected int defaultTextIconGap = 4;
 131:   
 132:   /**
 133:    * Color of the text when menu item is disabled
 134:    */
 135:   protected Color disabledForeground;
 136: 
 137:   /**
 138:    * The menu Drag mouse listener listening to the menu item.
 139:    */
 140:   protected MenuDragMouseListener menuDragMouseListener;
 141: 
 142:   /**
 143:    * The menu item itself
 144:    */
 145:   protected JMenuItem menuItem;
 146: 
 147:   /**
 148:    * Menu Key listener listening to the menu item.
 149:    */
 150:   protected MenuKeyListener menuKeyListener;
 151: 
 152:   /**
 153:    * mouse input listener listening to menu item.
 154:    */
 155:   protected MouseInputListener mouseInputListener;
 156: 
 157:   /**
 158:    * Indicates if border should be painted
 159:    */
 160:   protected boolean oldBorderPainted;
 161: 
 162:   /**
 163:    * Color of text that is used when menu item is selected
 164:    */
 165:   protected Color selectionBackground;
 166: 
 167:   /**
 168:    * Color of the text that is used when menu item is selected.
 169:    */
 170:   protected Color selectionForeground;
 171: 
 172:   /**
 173:    * String that separates description of the modifiers and the key
 174:    */
 175:   private String acceleratorDelimiter;
 176: 
 177:   /**
 178:    * ItemListener to listen for item changes in the menu item
 179:    */
 180:   private ItemListener itemListener;
 181: 
 182:   /**
 183:    * Number of spaces between accelerator and menu item's label.
 184:    */
 185:   private int defaultAcceleratorLabelGap = 10;
 186: 
 187:   /**
 188:    * The gap between different menus on the MenuBar.
 189:    */
 190:   private int MenuGap = 10;
 191:   
 192:   /** A PropertyChangeListener to make UI updates after property changes **/
 193:   PropertyChangeHandler propertyChangeListener;
 194: 
 195:   /**
 196:    * The view rectangle used for layout of the menu item.
 197:    */
 198:   private Rectangle viewRect;
 199: 
 200:   /**
 201:    * The rectangle that holds the area of the label.
 202:    */
 203:   private Rectangle textRect;
 204: 
 205:   /**
 206:    * The rectangle that holds the area of the accelerator.
 207:    */
 208:   private Rectangle accelRect;
 209: 
 210:   /**
 211:    * The rectangle that holds the area of the icon.
 212:    */
 213:   private Rectangle iconRect;
 214: 
 215:   /**
 216:    * The rectangle that holds the area of the icon.
 217:    */
 218:   private Rectangle arrowIconRect;
 219: 
 220:   /**
 221:    * The rectangle that holds the area of the check icon.
 222:    */
 223:   private Rectangle checkIconRect;
 224: 
 225:   /**
 226:    * A rectangle used for temporary storage to avoid creation of new
 227:    * rectangles.
 228:    */
 229:   private Rectangle cachedRect;
 230: 
 231:   /**
 232:    * A class to handle PropertChangeEvents for the JMenuItem
 233:    * @author Anthony Balkissoon abalkiss at redhat dot com.   
 234:    */
 235:   class PropertyChangeHandler implements PropertyChangeListener
 236:   {
 237:     /**
 238:      * This method is called when a property of the menuItem is changed.
 239:      * Currently it is only used to update the accelerator key bindings.
 240:      * 
 241:      * @param e
 242:      *          the PropertyChangeEvent
 243:      */
 244:     public void propertyChange(PropertyChangeEvent e)
 245:     {
 246:       String property = e.getPropertyName();
 247:       if (property.equals("accelerator"))
 248:         {
 249:           InputMap map = SwingUtilities.getUIInputMap(menuItem, 
 250:               JComponent.WHEN_IN_FOCUSED_WINDOW);
 251:           if (map != null)
 252:             map.remove((KeyStroke) e.getOldValue());
 253:           else
 254:             map = new ComponentInputMapUIResource(menuItem);
 255: 
 256:           KeyStroke accelerator = (KeyStroke) e.getNewValue();
 257:           if (accelerator != null)
 258:             map.put(accelerator, "doClick");
 259:         }
 260:       // TextLayout caching for speed-up drawing of text.
 261:       else if ((property.equals(AbstractButton.TEXT_CHANGED_PROPERTY)
 262:                 || property.equals("font"))
 263:                && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D")
 264:                == null)
 265:                
 266:         {
 267:           AbstractButton b = (AbstractButton) e.getSource();
 268:           String text = b.getText();
 269:           if (text == null)
 270:             text = "";
 271:           FontRenderContext frc = new FontRenderContext(new AffineTransform(),
 272:                                                         false, false);
 273:           TextLayout layout = new TextLayout(text, b.getFont(), frc);
 274:           b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout);
 275:         }
 276:     }
 277:   }
 278:   
 279:   /**
 280:    * A class to handle accelerator keys.  This is the Action we will
 281:    * perform when the accelerator key for this JMenuItem is pressed.
 282:    * @author Anthony Balkissoon abalkiss at redhat dot com
 283:    *
 284:    */
 285:   class ClickAction extends AbstractAction
 286:   {
 287:     /**
 288:      * This is what is done when the accelerator key for the JMenuItem is
 289:      * pressed.
 290:      */
 291:     public void actionPerformed(ActionEvent event)
 292:     {
 293:       doClick(MenuSelectionManager.defaultManager());
 294:     }    
 295:   }
 296:   
 297:   /**
 298:    * Creates a new BasicMenuItemUI object.
 299:    */
 300:   public BasicMenuItemUI()
 301:   {
 302:     mouseInputListener = createMouseInputListener(menuItem);
 303:     menuDragMouseListener = createMenuDragMouseListener(menuItem);
 304:     menuKeyListener = createMenuKeyListener(menuItem);
 305:     itemListener = new ItemHandler();
 306:     propertyChangeListener = new PropertyChangeHandler();
 307: 
 308:     // Initialize rectangles for layout.
 309:     viewRect = new Rectangle();
 310:     textRect = new Rectangle();
 311:     iconRect = new Rectangle();
 312:     arrowIconRect = new Rectangle();
 313:     checkIconRect = new Rectangle();
 314:     accelRect = new Rectangle();
 315:     cachedRect = new Rectangle();
 316:   }
 317: 
 318:   /**
 319:    * Create MenuDragMouseListener to listen for mouse dragged events.
 320:    * 
 321:    * @param c
 322:    *          menu item to listen to
 323:    * @return The MenuDragMouseListener
 324:    */
 325:   protected MenuDragMouseListener createMenuDragMouseListener(JComponent c)
 326:   {
 327:     return new MenuDragMouseHandler();
 328:   }
 329: 
 330:   /**
 331:    * Creates MenuKeyListener to listen to key events occuring when menu item is
 332:    * visible on the screen.
 333:    * 
 334:    * @param c
 335:    *          menu item to listen to
 336:    * @return The MenuKeyListener
 337:    */
 338:   protected MenuKeyListener createMenuKeyListener(JComponent c)
 339:   {
 340:     return new MenuKeyHandler();
 341:   }
 342: 
 343:   /**
 344:    * Handles mouse input events occuring for this menu item
 345:    * 
 346:    * @param c
 347:    *          menu item to listen to
 348:    * @return The MouseInputListener
 349:    */
 350:   protected MouseInputListener createMouseInputListener(JComponent c)
 351:   {
 352:     return new MouseInputHandler();
 353:   }
 354: 
 355:   /**
 356:    * Factory method to create a BasicMenuItemUI for the given {@link
 357:    * JComponent}, which should be a {@link JMenuItem}.
 358:    * 
 359:    * @param c
 360:    *          The {@link JComponent} a UI is being created for.
 361:    * @return A BasicMenuItemUI for the {@link JComponent}.
 362:    */
 363:   public static ComponentUI createUI(JComponent c)
 364:   {
 365:     return new BasicMenuItemUI();
 366:   }
 367: 
 368:   /**
 369:    * Programatically clicks menu item.
 370:    * 
 371:    * @param msm
 372:    *          MenuSelectionManager for the menu hierarchy
 373:    */
 374:   protected void doClick(MenuSelectionManager msm)
 375:   {
 376:     menuItem.doClick();
 377:     msm.clearSelectedPath();
 378:   }
 379: 
 380:   /**
 381:    * Returns maximum size for the specified menu item
 382:    * 
 383:    * @param c
 384:    *          component for which to get maximum size
 385:    * @return Maximum size for the specified menu item.
 386:    */
 387:   public Dimension getMaximumSize(JComponent c)
 388:   {
 389:     return null;
 390:   }
 391: 
 392:   /**
 393:    * Returns minimum size for the specified menu item
 394:    * 
 395:    * @param c
 396:    *          component for which to get minimum size
 397:    * @return Minimum size for the specified menu item.
 398:    */
 399:   public Dimension getMinimumSize(JComponent c)
 400:   {
 401:     return null;
 402:   }
 403: 
 404:   /**
 405:    * Returns path to this menu item.
 406:    * 
 407:    * @return $MenuElement[]$ Returns array of menu elements that constitute a
 408:    *         path to this menu item.
 409:    */
 410:   public MenuElement[] getPath()
 411:   {
 412:     ArrayList path = new ArrayList();
 413: 
 414:     // Path to menu should also include its popup menu.
 415:     if (menuItem instanceof JMenu)
 416:       path.add(((JMenu) menuItem).getPopupMenu());
 417: 
 418:     Component c = menuItem;
 419:     while (c instanceof MenuElement)
 420:       {
 421:         path.add(0, (MenuElement) c);
 422: 
 423:         if (c instanceof JPopupMenu)
 424:           c = ((JPopupMenu) c).getInvoker();
 425:         else
 426:           c = c.getParent();
 427:       }
 428: 
 429:     MenuElement[] pathArray = new MenuElement[path.size()];
 430:     path.toArray(pathArray);
 431:     return pathArray;
 432:   }
 433: 
 434:   /**
 435:    * Returns preferred size for the given menu item.
 436:    * 
 437:    * @param c
 438:    *          menu item for which to get preferred size
 439:    * @param checkIcon
 440:    *          check icon displayed in the given menu item
 441:    * @param arrowIcon
 442:    *          arrow icon displayed in the given menu item
 443:    * @param defaultTextIconGap
 444:    *          space between icon and text in the given menuItem
 445:    * @return $Dimension$ preferred size for the given menu item
 446:    */
 447:   protected Dimension getPreferredMenuItemSize(JComponent c, Icon checkIcon,
 448:                                                Icon arrowIcon,
 449:                                                int defaultTextIconGap)
 450:   {
 451:     JMenuItem m = (JMenuItem) c;
 452:     String accelText = getAcceleratorString(m);
 453: 
 454:     // Layout the menu item. The result gets stored in the rectangle
 455:     // fields of this class.
 456:     layoutMenuItem(m, accelText);
 457: 
 458:     // The union of the text and icon areas is the label area.
 459:     cachedRect.setBounds(textRect);
 460:     Rectangle pref = SwingUtilities.computeUnion(iconRect.x, iconRect.y,
 461:                                                  iconRect.width,
 462:                                                  iconRect.height,
 463:                                                  cachedRect);
 464: 
 465:     // Find the widest menu item text and accelerator and store it in
 466:     // client properties of the parent, so that we can align the accelerators
 467:     // properly. Of course, we only need can do this, if the parent is
 468:     // a JComponent and this menu item is not a toplevel menu.
 469:     Container parent = m.getParent();
 470:     if (parent != null && parent instanceof JComponent
 471:         && !(m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
 472:       {
 473:         JComponent p = (JComponent) parent;
 474: 
 475:         // The widest text so far.
 476:         Integer maxTextWidth = (Integer) p.getClientProperty("maxTextWidth");
 477:         int maxTextValue = maxTextWidth == null ? 0 : maxTextWidth.intValue();
 478:         if (pref.width < maxTextValue)
 479:           pref.width = maxTextValue;
 480:         else
 481:           p.putClientProperty("maxTextWidth", new Integer(pref.width));
 482: 
 483:         // The widest accelerator so far.
 484:         Integer maxAccelWidth = (Integer) p.getClientProperty("maxAccelWidth");
 485:         int maxAccelValue = maxAccelWidth == null ? 0
 486:                                                   : maxAccelWidth.intValue();
 487:         if (accelRect.width > maxAccelValue)
 488:           {
 489:             maxAccelValue = accelRect.width;
 490:             p.putClientProperty("maxAccelWidth", new Integer(accelRect.width));
 491:           }
 492:         pref.width += maxAccelValue;
 493:         pref.width += defaultTextIconGap;
 494:       }
 495: 
 496:     // Add arrow and check size if appropriate.
 497:     if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
 498:       {
 499:         pref.width += checkIconRect.width;
 500:         pref.width += defaultTextIconGap;
 501:         pref.width += arrowIconRect.width;
 502:         pref.width += defaultTextIconGap;
 503:       }
 504: 
 505:     // Add a gap ~2 times as wide as the defaultTextIconGap.
 506:     pref.width += 2 * defaultTextIconGap;
 507: 
 508:     // Respect the insets of the menu item.
 509:     Insets i = m.getInsets();
 510:     pref.width += i.left + i.right;
 511:     pref.height += i.top + i.bottom;
 512: 
 513:     // Return a copy, so that nobody messes with our textRect.
 514:     return pref.getSize();
 515:   }
 516: 
 517:   /**
 518:    * Returns preferred size of the given component
 519:    * 
 520:    * @param c
 521:    *          component for which to return preferred size
 522:    * @return $Dimension$ preferred size for the given component
 523:    */
 524:   public Dimension getPreferredSize(JComponent c)
 525:   {
 526:     return getPreferredMenuItemSize(c, checkIcon, arrowIcon, 
 527:                                     defaultTextIconGap);
 528:   }
 529: 
 530:   /**
 531:    * Returns the prefix for entries in the {@link UIDefaults} table.
 532:    * 
 533:    * @return "MenuItem"
 534:    */
 535:   protected String getPropertyPrefix()
 536:   {
 537:     return "MenuItem";
 538:   }
 539: 
 540:   /**
 541:    * This method installs the components for this {@link JMenuItem}.
 542:    * 
 543:    * @param menuItem
 544:    *          The {@link JMenuItem} to install components for.
 545:    */
 546:   protected void installComponents(JMenuItem menuItem)
 547:   {
 548:     // FIXME: Need to implement
 549:   }
 550: 
 551:   /**
 552:    * This method installs the defaults that are defined in the Basic look and
 553:    * feel for this {@link JMenuItem}.
 554:    */
 555:   protected void installDefaults()
 556:   {
 557:     String prefix = getPropertyPrefix();
 558:     LookAndFeel.installBorder(menuItem, prefix + ".border");
 559:     LookAndFeel.installColorsAndFont(menuItem, prefix + ".background",
 560:                                      prefix + ".foreground", prefix + ".font");
 561:     menuItem.setMargin(UIManager.getInsets(prefix + ".margin"));
 562:     acceleratorFont = UIManager.getFont(prefix + ".acceleratorFont");
 563:     acceleratorForeground = UIManager.getColor(prefix 
 564:         + ".acceleratorForeground");
 565:     acceleratorSelectionForeground = UIManager.getColor(prefix 
 566:         + ".acceleratorSelectionForeground");
 567:     selectionBackground = UIManager.getColor(prefix + ".selectionBackground");
 568:     selectionForeground = UIManager.getColor(prefix + ".selectionForeground");
 569:     acceleratorDelimiter = UIManager.getString(prefix + ".acceleratorDelimiter");
 570:     checkIcon = UIManager.getIcon(prefix + ".checkIcon");
 571:     
 572:     menuItem.setHorizontalTextPosition(SwingConstants.TRAILING);
 573:     menuItem.setHorizontalAlignment(SwingConstants.LEADING);
 574:   }
 575: 
 576:   /**
 577:    * This method installs the keyboard actions for this {@link JMenuItem}.
 578:    */
 579:   protected void installKeyboardActions()
 580:   {
 581:     InputMap focusedWindowMap = SwingUtilities.getUIInputMap(menuItem, 
 582:         JComponent.WHEN_IN_FOCUSED_WINDOW);
 583:     if (focusedWindowMap == null)
 584:       focusedWindowMap = new ComponentInputMapUIResource(menuItem);
 585:     KeyStroke accelerator = menuItem.getAccelerator();
 586:     if (accelerator != null)
 587:       focusedWindowMap.put(accelerator, "doClick");
 588:     SwingUtilities.replaceUIInputMap(menuItem, 
 589:         JComponent.WHEN_IN_FOCUSED_WINDOW, focusedWindowMap);
 590:     
 591:     ActionMap UIActionMap = SwingUtilities.getUIActionMap(menuItem);
 592:     if (UIActionMap == null)
 593:       UIActionMap = new ActionMapUIResource();
 594:     UIActionMap.put("doClick", new ClickAction());
 595:     SwingUtilities.replaceUIActionMap(menuItem, UIActionMap);
 596:   }
 597: 
 598:   /**
 599:    * This method installs the listeners for the {@link JMenuItem}.
 600:    */
 601:   protected void installListeners()
 602:   {
 603:     menuItem.addMouseListener(mouseInputListener);
 604:     menuItem.addMouseMotionListener(mouseInputListener);
 605:     menuItem.addMenuDragMouseListener(menuDragMouseListener);
 606:     menuItem.addMenuKeyListener(menuKeyListener);
 607:     menuItem.addItemListener(itemListener);
 608:     menuItem.addPropertyChangeListener(propertyChangeListener);
 609:   }
 610: 
 611:   /**
 612:    * Installs and initializes all fields for this UI delegate. Any properties of
 613:    * the UI that need to be initialized and/or set to defaults will be done now.
 614:    * It will also install any listeners necessary.
 615:    * 
 616:    * @param c
 617:    *          The {@link JComponent} that is having this UI installed.
 618:    */
 619:   public void installUI(JComponent c)
 620:   {
 621:     super.installUI(c);
 622:     menuItem = (JMenuItem) c;
 623:     installDefaults();
 624:     installComponents(menuItem);
 625:     installListeners();
 626:     installKeyboardActions();
 627:   }
 628: 
 629:   /**
 630:    * Paints given menu item using specified graphics context
 631:    * 
 632:    * @param g
 633:    *          The graphics context used to paint this menu item
 634:    * @param c
 635:    *          Menu Item to paint
 636:    */
 637:   public void paint(Graphics g, JComponent c)
 638:   {
 639:     paintMenuItem(g, c, checkIcon, arrowIcon, selectionBackground,
 640:                   c.getForeground(), defaultTextIconGap);
 641:   }
 642: 
 643:   /**
 644:    * Paints background of the menu item
 645:    * 
 646:    * @param g
 647:    *          The graphics context used to paint this menu item
 648:    * @param menuItem
 649:    *          menu item to paint
 650:    * @param bgColor
 651:    *          Background color to use when painting menu item
 652:    */
 653:   protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor)
 654:   {
 655:     // Menu item is considered to be highlighted when it is selected.
 656:     // But we don't want to paint the background of JCheckBoxMenuItems
 657:     ButtonModel mod = menuItem.getModel();
 658:     Color saved = g.getColor();
 659:     if (mod.isArmed() || ((menuItem instanceof JMenu) && mod.isSelected()))
 660:       {
 661:         g.setColor(bgColor);
 662:         g.fillRect(0, 0, menuItem.getWidth(), menuItem.getHeight());
 663:       }
 664:     else if (menuItem.isOpaque())
 665:       {
 666:         g.setColor(menuItem.getBackground());
 667:         g.fillRect(0, 0, menuItem.getWidth(), menuItem.getHeight());
 668:       }
 669:     g.setColor(saved);
 670:   }
 671: 
 672:   /**
 673:    * Paints specified menu item
 674:    * 
 675:    * @param g
 676:    *          The graphics context used to paint this menu item
 677:    * @param c
 678:    *          menu item to paint
 679:    * @param checkIcon
 680:    *          check icon to use when painting menu item
 681:    * @param arrowIcon
 682:    *          arrow icon to use when painting menu item
 683:    * @param background
 684:    *          Background color of the menu item
 685:    * @param foreground
 686:    *          Foreground color of the menu item
 687:    * @param defaultTextIconGap
 688:    *          space to use between icon and text when painting menu item
 689:    */
 690:   protected void paintMenuItem(Graphics g, JComponent c, Icon checkIcon,
 691:                                Icon arrowIcon, Color background,
 692:                                Color foreground, int defaultTextIconGap)
 693:   {
 694:     JMenuItem m = (JMenuItem) c;
 695: 
 696:     // Fetch fonts.
 697:     Font oldFont = g.getFont();
 698:     Font font = c.getFont();
 699:     g.setFont(font);
 700:     FontMetrics accelFm = m.getFontMetrics(acceleratorFont);
 701: 
 702:     // Create accelerator string.
 703:     String accelText = getAcceleratorString(m);
 704: 
 705:     // Layout menu item. The result gets stored in the rectangle fields
 706:     // of this class.
 707:     layoutMenuItem(m, accelText);
 708: 
 709:     // Paint the background.
 710:     paintBackground(g, m, background);
 711: 
 712:     Color oldColor = g.getColor();
 713: 
 714:     // Paint the check icon.
 715:     if (checkIcon != null)
 716:       {
 717:         checkIcon.paintIcon(m, g, checkIconRect.x, checkIconRect.y);
 718:       }
 719: 
 720:     // Paint the icon.
 721:     ButtonModel model = m.getModel();
 722:     if (m.getIcon() != null)
 723:       {
 724:         // Determine icon depending on the menu item
 725:         // state (normal/disabled/pressed).
 726:         Icon icon;
 727:         if (! m.isEnabled())
 728:           {
 729:             icon = m.getDisabledIcon();
 730:           }
 731:         else if (model.isPressed() && model.isArmed())
 732:           {
 733:             icon = m.getPressedIcon();
 734:             if (icon == null)
 735:               {
 736:                 icon = m.getIcon();
 737:               }
 738:           }
 739:         else
 740:           {
 741:             icon = m.getIcon();
 742:           }
 743: 
 744:         if (icon != null)
 745:           {
 746:             icon.paintIcon(m, g, iconRect.x, iconRect.y);
 747:           }
 748:       }
 749: 
 750:     // Paint the text.
 751:     String text = m.getText();
 752:     if (text != null)
 753:       {
 754:         // Handle HTML.
 755:         View html = (View) m.getClientProperty(BasicHTML.propertyKey);
 756:         if (html != null)
 757:           {
 758:             html.paint(g, textRect);
 759:           }
 760:         else
 761:           {
 762:             paintText(g, m, textRect, text);
 763:           }
 764:       }
 765: 
 766:     // Paint accelerator text.
 767:     if (! accelText.equals(""))
 768:       {
 769:         // Align the accelerator text. In getPreferredMenuItemSize() we
 770:         // store a client property 'maxAccelWidth' in the parent which holds
 771:         // the maximum accelerator width for the children of this parent.
 772:         // We use this here to align the accelerators properly.
 773:         int accelOffset = 0;
 774:         Container parent = m.getParent();
 775:         if (parent != null && parent instanceof JComponent)
 776:           {
 777:             JComponent p = (JComponent) parent;
 778:             Integer maxAccelWidth =
 779:               (Integer) p.getClientProperty("maxAccelWidth");
 780:             int maxAccelValue = maxAccelWidth == null ? 0
 781:                                                     : maxAccelWidth.intValue();
 782:             accelOffset = maxAccelValue - accelRect.width;
 783:           }
 784: 
 785:         g.setFont(acceleratorFont);
 786:         if (! m.isEnabled())
 787:           {
 788:             // Paint accelerator disabled.
 789:             g.setColor(disabledForeground);
 790:           }
 791:         else
 792:           {
 793:             if (m.isArmed() || (m instanceof JMenu && m.isSelected()))
 794:               g.setColor(acceleratorSelectionForeground);
 795:             else
 796:               g.setColor(acceleratorForeground);
 797:           }
 798:         g.drawString(accelText, accelRect.x - accelOffset,
 799:                      accelRect.y + accelFm.getAscent());
 800:       }
 801: 
 802:     // Paint arrow.
 803:     if (arrowIcon != null
 804:         && ! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
 805:       {
 806:         arrowIcon.paintIcon(m, g, arrowIconRect.x, arrowIconRect.y);
 807:       }
 808: 
 809:     g.setFont(oldFont);
 810:     g.setColor(oldColor);
 811: 
 812:   }
 813: 
 814:   /**
 815:    * Paints label for the given menu item
 816:    * 
 817:    * @param g
 818:    *          The graphics context used to paint this menu item
 819:    * @param menuItem
 820:    *          menu item for which to draw its label
 821:    * @param textRect
 822:    *          rectangle specifiying position of the text relative to the given
 823:    *          menu item
 824:    * @param text
 825:    *          label of the menu item
 826:    */
 827:   protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect,
 828:                            String text)
 829:   {
 830:     Font f = menuItem.getFont();
 831:     g.setFont(f);
 832:     FontMetrics fm = g.getFontMetrics(f);
 833: 
 834:     if (text != null && !text.equals(""))
 835:       {
 836:         if (menuItem.isEnabled())
 837:           {
 838:             // Menu item is considered to be highlighted when it is selected.
 839:             // But not if it's a JCheckBoxMenuItem
 840:             ButtonModel mod = menuItem.getModel();
 841:             if ((menuItem.isSelected() && checkIcon == null)
 842:                 || (mod != null && mod.isArmed())
 843:                 && (menuItem.getParent() instanceof MenuElement))
 844:               g.setColor(selectionForeground);
 845:             else
 846:               g.setColor(menuItem.getForeground());
 847:           }
 848:         else
 849:           // FIXME: should fix this to use 'disabledForeground', but its
 850:           // default value in BasicLookAndFeel is null.
 851: 
 852:           // FIXME: should there be different foreground colours for selected
 853:           // or deselected, when disabled?
 854:           g.setColor(Color.gray);
 855: 
 856:         int mnemonicIndex = menuItem.getDisplayedMnemonicIndex();
 857: 
 858:         if (mnemonicIndex != -1)
 859:           BasicGraphicsUtils.drawStringUnderlineCharAt(menuItem, g, text,
 860:                                                        mnemonicIndex,
 861:                                                        textRect.x,
 862:                                                        textRect.y
 863:                                                            + fm.getAscent());
 864:         else
 865:           BasicGraphicsUtils.drawString(menuItem, g, text, 0, textRect.x,
 866:                                         textRect.y + fm.getAscent());
 867:       }
 868:   }
 869: 
 870:   /**
 871:    * This method uninstalls the components for this {@link JMenuItem}.
 872:    * 
 873:    * @param menuItem
 874:    *          The {@link JMenuItem} to uninstall components for.
 875:    */
 876:   protected void uninstallComponents(JMenuItem menuItem)
 877:   {
 878:     // FIXME: need to implement
 879:   }
 880: 
 881:   /**
 882:    * This method uninstalls the defaults and sets any objects created during
 883:    * install to null
 884:    */
 885:   protected void uninstallDefaults()
 886:   {
 887:     menuItem.setForeground(null);
 888:     menuItem.setBackground(null);
 889:     menuItem.setBorder(null);
 890:     menuItem.setMargin(null);
 891:     menuItem.setBackground(null);
 892:     menuItem.setBorder(null);
 893:     menuItem.setFont(null);
 894:     menuItem.setForeground(null);
 895:     menuItem.setMargin(null);
 896:     acceleratorFont = null;
 897:     acceleratorForeground = null;
 898:     acceleratorSelectionForeground = null;
 899:     arrowIcon = null;
 900:     selectionBackground = null;
 901:     selectionForeground = null;
 902:     acceleratorDelimiter = null;
 903:   }
 904: 
 905:   /**
 906:    * Uninstalls any keyboard actions.
 907:    */
 908:   protected void uninstallKeyboardActions()
 909:   {   
 910:     SwingUtilities.replaceUIInputMap(menuItem,
 911:                                      JComponent.WHEN_IN_FOCUSED_WINDOW, null);
 912:   }
 913: 
 914:   /**
 915:    * Unregisters all the listeners that this UI delegate was using.
 916:    */
 917:   protected void uninstallListeners()
 918:   {
 919:     menuItem.removeMouseListener(mouseInputListener);
 920:     menuItem.removeMenuDragMouseListener(menuDragMouseListener);
 921:     menuItem.removeMenuKeyListener(menuKeyListener);
 922:     menuItem.removeItemListener(itemListener);
 923:     menuItem.removePropertyChangeListener(propertyChangeListener);
 924:   }
 925: 
 926:   /**
 927:    * Performs the opposite of installUI. Any properties or resources that need
 928:    * to be cleaned up will be done now. It will also uninstall any listeners it
 929:    * has. In addition, any properties of this UI will be nulled.
 930:    * 
 931:    * @param c
 932:    *          The {@link JComponent} that is having this UI uninstalled.
 933:    */
 934:   public void uninstallUI(JComponent c)
 935:   {
 936:     uninstallListeners();
 937:     uninstallDefaults();
 938:     uninstallComponents(menuItem);
 939:     menuItem = null;
 940:   }
 941: 
 942:   /**
 943:    * This method calls paint.
 944:    * 
 945:    * @param g
 946:    *          The graphics context used to paint this menu item
 947:    * @param c
 948:    *          The menu item to paint
 949:    */
 950:   public void update(Graphics g, JComponent c)
 951:   {
 952:     paint(g, c);
 953:   }
 954: 
 955:   /**
 956:    * Return text representation of the specified accelerator
 957:    * 
 958:    * @param accelerator
 959:    *          Accelerator for which to return string representation
 960:    * @return $String$ Text representation of the given accelerator
 961:    */
 962:   private String getAcceleratorText(KeyStroke accelerator)
 963:   {
 964:     // convert keystroke into string format
 965:     String modifiersText = "";
 966:     int modifiers = accelerator.getModifiers();
 967:     char keyChar = accelerator.getKeyChar();
 968:     int keyCode = accelerator.getKeyCode();
 969: 
 970:     if (modifiers != 0)
 971:       modifiersText = KeyEvent.getKeyModifiersText(modifiers)
 972:                       + acceleratorDelimiter;
 973: 
 974:     if (keyCode == KeyEvent.VK_UNDEFINED)
 975:       return modifiersText + keyChar;
 976:     else
 977:       return modifiersText + KeyEvent.getKeyText(keyCode);
 978:   }
 979: 
 980:   /**
 981:    * Calculates and return rectange in which accelerator should be displayed
 982:    * 
 983:    * @param accelerator
 984:    *          accelerator for which to return the display rectangle
 985:    * @param fm
 986:    *          The font metrics used to measure the text
 987:    * @return $Rectangle$ reactangle which will be used to display accelerator
 988:    */
 989:   private Rectangle getAcceleratorRect(KeyStroke accelerator, FontMetrics fm)
 990:   {
 991:     int width = fm.stringWidth(getAcceleratorText(accelerator));
 992:     int height = fm.getHeight();
 993:     return new Rectangle(0, 0, width, height);
 994:   }
 995: 
 996:   /**
 997:    * This class handles mouse events occuring inside the menu item. Most of the
 998:    * events are forwarded for processing to MenuSelectionManager of the current
 999:    * menu hierarchy.
1000:    */
1001:   protected class MouseInputHandler implements MouseInputListener
1002:   {
1003:     /**
1004:      * Creates a new MouseInputHandler object.
1005:      */
1006:     protected MouseInputHandler()
1007:     {
1008:       // Nothing to do here.
1009:     }
1010: 
1011:     /**
1012:      * This method is called when mouse is clicked on the menu item. It forwards
1013:      * this event to MenuSelectionManager.
1014:      * 
1015:      * @param e
1016:      *          A {@link MouseEvent}.
1017:      */
1018:     public void mouseClicked(MouseEvent e)
1019:     {
1020:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1021:       manager.processMouseEvent(e);
1022:     }
1023: 
1024:     /**
1025:      * This method is called when mouse is dragged inside the menu item. It
1026:      * forwards this event to MenuSelectionManager.
1027:      * 
1028:      * @param e
1029:      *          A {@link MouseEvent}.
1030:      */
1031:     public void mouseDragged(MouseEvent e)
1032:     {
1033:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1034:       manager.processMouseEvent(e);
1035:     }
1036: 
1037:     /**
1038:      * This method is called when mouse enters menu item. When this happens menu
1039:      * item is considered to be selected and selection path in
1040:      * MenuSelectionManager is set. This event is also forwarded to
1041:      * MenuSelection Manager for further processing.
1042:      * 
1043:      * @param e
1044:      *          A {@link MouseEvent}.
1045:      */
1046:     public void mouseEntered(MouseEvent e)
1047:     {
1048:       Component source = (Component) e.getSource();
1049:       if (source.getParent() instanceof MenuElement)
1050:         {
1051:           MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1052:           manager.setSelectedPath(getPath());
1053:           manager.processMouseEvent(e);
1054:         }
1055:     }
1056: 
1057:     /**
1058:      * This method is called when mouse exits menu item. The event is forwarded
1059:      * to MenuSelectionManager for processing.
1060:      * 
1061:      * @param e
1062:      *          A {@link MouseEvent}.
1063:      */
1064:     public void mouseExited(MouseEvent e)
1065:     {
1066:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1067:       manager.processMouseEvent(e);
1068:     }
1069: 
1070:     /**
1071:      * This method is called when mouse is inside the menu item. This event is
1072:      * forwarder to MenuSelectionManager for further processing.
1073:      * 
1074:      * @param e
1075:      *          A {@link MouseEvent}.
1076:      */
1077:     public void mouseMoved(MouseEvent e)
1078:     {
1079:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1080:       manager.processMouseEvent(e);
1081:     }
1082: 
1083:     /**
1084:      * This method is called when mouse is pressed. This event is forwarded to
1085:      * MenuSelectionManager for further processing.
1086:      * 
1087:      * @param e
1088:      *          A {@link MouseEvent}.
1089:      */
1090:     public void mousePressed(MouseEvent e)
1091:     {
1092:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1093:       manager.processMouseEvent(e);
1094:     }
1095: 
1096:     /**
1097:      * This method is called when mouse is released. If the mouse is released
1098:      * inside this menuItem, then this menu item is considered to be chosen and
1099:      * the menu hierarchy should be closed.
1100:      * 
1101:      * @param e
1102:      *          A {@link MouseEvent}.
1103:      */
1104:     public void mouseReleased(MouseEvent e)
1105:     {
1106:       Rectangle size = menuItem.getBounds();
1107:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1108:       if (e.getX() > 0 && e.getX() < size.width && e.getY() > 0
1109:           && e.getY() < size.height)
1110:         {
1111:           manager.clearSelectedPath();
1112:           menuItem.doClick();
1113:         }
1114: 
1115:       else
1116:         manager.processMouseEvent(e);
1117:     }
1118:   }
1119: 
1120:   /**
1121:    * This class handles mouse dragged events.
1122:    */
1123:   private class MenuDragMouseHandler implements MenuDragMouseListener
1124:   {
1125:     /**
1126:      * Tbis method is invoked when mouse is dragged over the menu item.
1127:      * 
1128:      * @param e
1129:      *          The MenuDragMouseEvent
1130:      */
1131:     public void menuDragMouseDragged(MenuDragMouseEvent e)
1132:     {
1133:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1134:       manager.setSelectedPath(e.getPath());
1135:     }
1136: 
1137:     /**
1138:      * Tbis method is invoked when mouse enters the menu item while it is being
1139:      * dragged.
1140:      * 
1141:      * @param e
1142:      *          The MenuDragMouseEvent
1143:      */
1144:     public void menuDragMouseEntered(MenuDragMouseEvent e)
1145:     {
1146:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1147:       manager.setSelectedPath(e.getPath());
1148:     }
1149: 
1150:     /**
1151:      * Tbis method is invoked when mouse exits the menu item while it is being
1152:      * dragged
1153:      * 
1154:      * @param e the MenuDragMouseEvent
1155:      */
1156:     public void menuDragMouseExited(MenuDragMouseEvent e)
1157:     {
1158:       // TODO: What should be done here, if anything?
1159:     }
1160: 
1161:     /**
1162:      * Tbis method is invoked when mouse was dragged and released inside the
1163:      * menu item.
1164:      * 
1165:      * @param e
1166:      *          The MenuDragMouseEvent
1167:      */
1168:     public void menuDragMouseReleased(MenuDragMouseEvent e)
1169:     {
1170:       MenuElement[] path = e.getPath();
1171: 
1172:       if (path[path.length - 1] instanceof JMenuItem)
1173:         ((JMenuItem) path[path.length - 1]).doClick();
1174: 
1175:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1176:       manager.clearSelectedPath();
1177:     }
1178:   }
1179: 
1180:   /**
1181:    * This class handles key events occuring when menu item is visible on the
1182:    * screen.
1183:    */
1184:   private class MenuKeyHandler implements MenuKeyListener
1185:   {
1186:     /**
1187:      * This method is invoked when key has been pressed
1188:      * 
1189:      * @param e
1190:      *          A {@link MenuKeyEvent}.
1191:      */
1192:     public void menuKeyPressed(MenuKeyEvent e)
1193:     {
1194:       // TODO: What should be done here, if anything?
1195:     }
1196: 
1197:     /**
1198:      * This method is invoked when key has been pressed
1199:      * 
1200:      * @param e
1201:      *          A {@link MenuKeyEvent}.
1202:      */
1203:     public void menuKeyReleased(MenuKeyEvent e)
1204:     {
1205:       // TODO: What should be done here, if anything?
1206:     }
1207: 
1208:     /**
1209:      * This method is invoked when key has been typed It handles the mnemonic
1210:      * key for the menu item.
1211:      * 
1212:      * @param e
1213:      *          A {@link MenuKeyEvent}.
1214:      */
1215:     public void menuKeyTyped(MenuKeyEvent e)
1216:     {
1217:       // TODO: What should be done here, if anything?
1218:     }
1219:   }
1220:   
1221:   /**
1222:    * Helper class that listens for item changes to the properties of the {@link
1223:    * JMenuItem}.
1224:    */
1225:   private class ItemHandler implements ItemListener
1226:   {
1227:     /**
1228:      * This method is called when one of the menu item changes.
1229:      *
1230:      * @param evt A {@link ItemEvent}.
1231:      */
1232:     public void itemStateChanged(ItemEvent evt)
1233:     {
1234:       boolean state = false;
1235:       if (menuItem instanceof JCheckBoxMenuItem)
1236:         {
1237:           if (evt.getStateChange() == ItemEvent.SELECTED)
1238:             state = true;
1239:           ((JCheckBoxMenuItem) menuItem).setState(state);
1240:         }
1241:       menuItem.revalidate();
1242:       menuItem.repaint();
1243:     }
1244:   }
1245: 
1246:   /**
1247:    * A helper method to create the accelerator string from the menu item's
1248:    * accelerator property. The returned string is empty if there is
1249:    * no accelerator defined.
1250:    *
1251:    * @param m the menu item
1252:    *
1253:    * @return the accelerator string, not null
1254:    */
1255:   private String getAcceleratorString(JMenuItem m)
1256:   {
1257:     // Create accelerator string.
1258:     KeyStroke accel = m.getAccelerator();
1259:     String accelText = "";
1260:     if (accel != null)
1261:       {
1262:         int mods = accel.getModifiers();
1263:         if (mods > 0)
1264:           {
1265:             accelText = KeyEvent.getKeyModifiersText(mods);
1266:             accelText += acceleratorDelimiter;
1267:           }
1268:         int keycode = accel.getKeyCode();
1269:         if (keycode != 0)
1270:           accelText += KeyEvent.getKeyText(keycode);
1271:         else
1272:           accelText += accel.getKeyChar();
1273:       }
1274:     return accelText;
1275:   }
1276: 
1277:   /**
1278:    * A helper method that lays out the menu item. The layout is stored
1279:    * in the fields of this class.
1280:    *
1281:    * @param m the menu item to layout
1282:    * @param accelText the accelerator text
1283:    */
1284:   private void layoutMenuItem(JMenuItem m, String accelText)
1285:   {
1286:     int width = m.getWidth();
1287:     int height = m.getHeight();
1288: 
1289:     // Reset rectangles.
1290:     iconRect.setBounds(0, 0, 0, 0);
1291:     textRect.setBounds(0, 0, 0, 0);
1292:     accelRect.setBounds(0, 0, 0, 0);
1293:     checkIconRect.setBounds(0, 0, 0, 0);
1294:     arrowIconRect.setBounds(0, 0, 0, 0);
1295:     viewRect.setBounds(0, 0, width, height);
1296: 
1297:     // Substract insets to the view rect.
1298:     Insets insets = m.getInsets();
1299:     viewRect.x += insets.left;
1300:     viewRect.y += insets.top;
1301:     viewRect.width -= insets.left + insets.right;
1302:     viewRect.height -= insets.top + insets.bottom;
1303: 
1304:     // Fetch the fonts.
1305:     Font font = m.getFont();
1306:     FontMetrics fm = m.getFontMetrics(font);
1307:     FontMetrics accelFm = m.getFontMetrics(acceleratorFont);
1308: 
1309:     String text = m.getText();
1310:     SwingUtilities.layoutCompoundLabel(m, fm, text, m.getIcon(),
1311:                                        m.getVerticalAlignment(),
1312:                                        m.getHorizontalAlignment(),
1313:                                        m.getVerticalTextPosition(),
1314:                                        m.getHorizontalTextPosition(),
1315:                                        viewRect, iconRect, textRect,
1316:                                        defaultTextIconGap);
1317: 
1318:     // Initialize accelerator width and height.
1319:     if (! accelText.equals(""))
1320:       {
1321:         accelRect.width = accelFm.stringWidth(accelText);
1322:         accelRect.height = accelFm.getHeight();
1323:       }
1324: 
1325:     // Initialize check and arrow icon width and height.
1326:     if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
1327:       {
1328:         if (checkIcon != null)
1329:           {
1330:             checkIconRect.width = checkIcon.getIconWidth();
1331:             checkIconRect.height = checkIcon.getIconHeight();
1332:           }
1333:         if (arrowIcon != null)
1334:           {
1335:             arrowIconRect.width = arrowIcon.getIconWidth();
1336:             arrowIconRect.height = arrowIcon.getIconHeight();
1337:           }
1338:       }
1339: 
1340:     // The union of the icon and text of the menu item is the 'label area'.
1341:     cachedRect.setBounds(textRect);
1342:     Rectangle labelRect = SwingUtilities.computeUnion(iconRect.x,
1343:                                                       iconRect.y,
1344:                                                       iconRect.width,
1345:                                                       iconRect.height,
1346:                                                       cachedRect);
1347:     textRect.x += defaultTextIconGap;
1348:     iconRect.x += defaultTextIconGap;
1349: 
1350:     // Layout accelerator rect.
1351:     accelRect.x = viewRect.x + viewRect.width - arrowIconRect.width
1352:       - defaultTextIconGap - accelRect.width;
1353:     // Layout check and arrow icons only when not in toplevel menu.
1354:     if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
1355:       {
1356:         checkIconRect.x = viewRect.x + defaultTextIconGap;
1357:         textRect.x += defaultTextIconGap + checkIconRect.width;
1358:         iconRect.x += defaultTextIconGap + checkIconRect.width;
1359:         arrowIconRect.x = viewRect.x + viewRect.width - defaultTextIconGap
1360:           - arrowIconRect.width;
1361:       }
1362: 
1363:     // Align the accelerator text and all the icons vertically centered to
1364:     // the menu text.
1365:     accelRect.y = labelRect.y + (labelRect.height / 2)
1366:       - (accelRect.height / 2);
1367:     if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
1368:       {
1369:         arrowIconRect.y = labelRect.y + (labelRect.height / 2)
1370:           - (arrowIconRect.height / 2);
1371:         checkIconRect.y = labelRect.y + (labelRect.height / 2)
1372:           - (checkIconRect.height / 2);
1373:       }
1374:   }
1375: }