Save This Page
Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]
    1   /*
    2    * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.swing.plaf.basic;
   27   
   28   import sun.swing.MenuItemCheckIconFactory;
   29   import sun.swing.SwingUtilities2;
   30   import static sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET;
   31   import java.awt;
   32   import java.awt.event;
   33   import java.beans.PropertyChangeEvent;
   34   import java.beans.PropertyChangeListener;
   35   
   36   import javax.swing;
   37   import javax.swing.event;
   38   import javax.swing.border;
   39   import javax.swing.plaf;
   40   import javax.swing.text.View;
   41   
   42   import sun.swing.UIAction;
   43   import sun.swing.StringUIClientPropertyKey;
   44   
   45   /**
   46    * BasicMenuItem implementation
   47    *
   48    * @author Georges Saab
   49    * @author David Karlton
   50    * @author Arnaud Weber
   51    * @author Fredrik Lagerblad
   52    */
   53   public class BasicMenuItemUI extends MenuItemUI
   54   {
   55       protected JMenuItem menuItem = null;
   56       protected Color selectionBackground;
   57       protected Color selectionForeground;
   58       protected Color disabledForeground;
   59       protected Color acceleratorForeground;
   60       protected Color acceleratorSelectionForeground;
   61       private   String acceleratorDelimiter;
   62   
   63       protected int defaultTextIconGap;
   64       protected Font acceleratorFont;
   65   
   66       protected MouseInputListener mouseInputListener;
   67       protected MenuDragMouseListener menuDragMouseListener;
   68       protected MenuKeyListener menuKeyListener;
   69       /**
   70        * <code>PropertyChangeListener</code> returned from
   71        * <code>createPropertyChangeListener</code>. You should not
   72        * need to access this field, rather if you want to customize the
   73        * <code>PropertyChangeListener</code> override
   74        * <code>createPropertyChangeListener</code>.
   75        *
   76        * @since 1.6
   77        * @see #createPropertyChangeListener
   78        */
   79       protected PropertyChangeListener propertyChangeListener;
   80       // BasicMenuUI also uses this.
   81       Handler handler;
   82   
   83       protected Icon arrowIcon = null;
   84       protected Icon checkIcon = null;
   85   
   86       protected boolean oldBorderPainted;
   87   
   88       /* diagnostic aids -- should be false for production builds. */
   89       private static final boolean TRACE =   false; // trace creates and disposes
   90   
   91       private static final boolean VERBOSE = false; // show reuse hits/misses
   92       private static final boolean DEBUG =   false;  // show bad params, misc.
   93   
   94       // Allows to reuse layoutInfo object.
   95       // Shouldn't be used directly. Use getLayoutInfo() instead.
   96       private final transient LayoutInfo layoutInfo = new LayoutInfo();
   97   
   98       /* Client Property keys for calculation of maximal widths */
   99       static final StringUIClientPropertyKey MAX_ARROW_WIDTH =
  100                           new StringUIClientPropertyKey("maxArrowWidth");
  101       static final StringUIClientPropertyKey MAX_CHECK_WIDTH =
  102                           new StringUIClientPropertyKey("maxCheckWidth");
  103       static final StringUIClientPropertyKey MAX_ICON_WIDTH =
  104                           new StringUIClientPropertyKey("maxIconWidth");
  105       static final StringUIClientPropertyKey MAX_TEXT_WIDTH =
  106                           new StringUIClientPropertyKey("maxTextWidth");
  107       static final StringUIClientPropertyKey MAX_ACC_WIDTH =
  108                           new StringUIClientPropertyKey("maxAccWidth");
  109       static final StringUIClientPropertyKey MAX_LABEL_WIDTH =
  110                           new StringUIClientPropertyKey("maxLabelWidth");
  111   
  112       static void loadActionMap(LazyActionMap map) {
  113           // NOTE: BasicMenuUI also calls into this method.
  114           map.put(new Actions(Actions.CLICK));
  115           BasicLookAndFeel.installAudioActionMap(map);
  116       }
  117   
  118       public static ComponentUI createUI(JComponent c) {
  119           return new BasicMenuItemUI();
  120       }
  121   
  122       public void installUI(JComponent c) {
  123           menuItem = (JMenuItem) c;
  124   
  125           installDefaults();
  126           installComponents(menuItem);
  127           installListeners();
  128           installKeyboardActions();
  129       }
  130   
  131   
  132       protected void installDefaults() {
  133           String prefix = getPropertyPrefix();
  134   
  135           acceleratorFont = UIManager.getFont("MenuItem.acceleratorFont");
  136   
  137           Object opaque = UIManager.get(getPropertyPrefix() + ".opaque");
  138           if (opaque != null) {
  139               LookAndFeel.installProperty(menuItem, "opaque", opaque);
  140           }
  141           else {
  142               LookAndFeel.installProperty(menuItem, "opaque", Boolean.TRUE);
  143           }
  144           if(menuItem.getMargin() == null ||
  145              (menuItem.getMargin() instanceof UIResource)) {
  146               menuItem.setMargin(UIManager.getInsets(prefix + ".margin"));
  147           }
  148   
  149           LookAndFeel.installProperty(menuItem, "iconTextGap", Integer.valueOf(4));
  150           defaultTextIconGap = menuItem.getIconTextGap();
  151   
  152           LookAndFeel.installBorder(menuItem, prefix + ".border");
  153           oldBorderPainted = menuItem.isBorderPainted();
  154           LookAndFeel.installProperty(menuItem, "borderPainted",
  155                                       UIManager.get(prefix + ".borderPainted"));
  156           LookAndFeel.installColorsAndFont(menuItem,
  157                                            prefix + ".background",
  158                                            prefix + ".foreground",
  159                                            prefix + ".font");
  160   
  161           // MenuItem specific defaults
  162           if (selectionBackground == null ||
  163               selectionBackground instanceof UIResource) {
  164               selectionBackground =
  165                   UIManager.getColor(prefix + ".selectionBackground");
  166           }
  167           if (selectionForeground == null ||
  168               selectionForeground instanceof UIResource) {
  169               selectionForeground =
  170                   UIManager.getColor(prefix + ".selectionForeground");
  171           }
  172           if (disabledForeground == null ||
  173               disabledForeground instanceof UIResource) {
  174               disabledForeground =
  175                   UIManager.getColor(prefix + ".disabledForeground");
  176           }
  177           if (acceleratorForeground == null ||
  178               acceleratorForeground instanceof UIResource) {
  179               acceleratorForeground =
  180                   UIManager.getColor(prefix + ".acceleratorForeground");
  181           }
  182           if (acceleratorSelectionForeground == null ||
  183               acceleratorSelectionForeground instanceof UIResource) {
  184               acceleratorSelectionForeground =
  185                   UIManager.getColor(prefix + ".acceleratorSelectionForeground");
  186           }
  187           // Get accelerator delimiter
  188           acceleratorDelimiter =
  189               UIManager.getString("MenuItem.acceleratorDelimiter");
  190           if (acceleratorDelimiter == null) { acceleratorDelimiter = "+"; }
  191           // Icons
  192           if (arrowIcon == null ||
  193               arrowIcon instanceof UIResource) {
  194               arrowIcon = UIManager.getIcon(prefix + ".arrowIcon");
  195           }
  196           if (checkIcon == null ||
  197               checkIcon instanceof UIResource) {
  198               checkIcon = UIManager.getIcon(prefix + ".checkIcon");
  199               //In case of column layout, .checkIconFactory is defined for this UI,
  200               //the icon is compatible with it and useCheckAndArrow() is true,
  201               //then the icon is handled by the checkIcon.
  202               boolean isColumnLayout = LayoutInfo.isColumnLayout(
  203                       BasicGraphicsUtils.isLeftToRight(menuItem), menuItem);
  204               if (isColumnLayout) {
  205                   MenuItemCheckIconFactory iconFactory =
  206                       (MenuItemCheckIconFactory) UIManager.get(prefix
  207                           + ".checkIconFactory");
  208                   if (iconFactory != null && useCheckAndArrow()
  209                           && iconFactory.isCompatible(checkIcon, prefix)) {
  210                       checkIcon = iconFactory.getIcon(menuItem);
  211                   }
  212               }
  213           }
  214       }
  215   
  216       /**
  217        * @since 1.3
  218        */
  219       protected void installComponents(JMenuItem menuItem){
  220           BasicHTML.updateRenderer(menuItem, menuItem.getText());
  221       }
  222   
  223       protected String getPropertyPrefix() {
  224           return "MenuItem";
  225       }
  226   
  227       protected void installListeners() {
  228           if ((mouseInputListener = createMouseInputListener(menuItem)) != null) {
  229               menuItem.addMouseListener(mouseInputListener);
  230               menuItem.addMouseMotionListener(mouseInputListener);
  231           }
  232           if ((menuDragMouseListener = createMenuDragMouseListener(menuItem)) != null) {
  233               menuItem.addMenuDragMouseListener(menuDragMouseListener);
  234           }
  235           if ((menuKeyListener = createMenuKeyListener(menuItem)) != null) {
  236               menuItem.addMenuKeyListener(menuKeyListener);
  237           }
  238           if ((propertyChangeListener = createPropertyChangeListener(menuItem)) != null) {
  239               menuItem.addPropertyChangeListener(propertyChangeListener);
  240           }
  241       }
  242   
  243       protected void installKeyboardActions() {
  244           installLazyActionMap();
  245           updateAcceleratorBinding();
  246       }
  247   
  248       void installLazyActionMap() {
  249           LazyActionMap.installLazyActionMap(menuItem, BasicMenuItemUI.class,
  250                                              getPropertyPrefix() + ".actionMap");
  251       }
  252   
  253       public void uninstallUI(JComponent c) {
  254           menuItem = (JMenuItem)c;
  255           uninstallDefaults();
  256           uninstallComponents(menuItem);
  257           uninstallListeners();
  258           uninstallKeyboardActions();
  259   
  260   
  261           // Remove values from the parent's Client Properties.
  262           JComponent p = getMenuItemParent(menuItem);
  263           if(p != null) {
  264               p.putClientProperty(BasicMenuItemUI.MAX_ARROW_WIDTH, null );
  265               p.putClientProperty(BasicMenuItemUI.MAX_CHECK_WIDTH, null );
  266               p.putClientProperty(BasicMenuItemUI.MAX_ACC_WIDTH, null );
  267               p.putClientProperty(BasicMenuItemUI.MAX_TEXT_WIDTH, null );
  268               p.putClientProperty(BasicMenuItemUI.MAX_ICON_WIDTH, null );
  269               p.putClientProperty(BasicMenuItemUI.MAX_LABEL_WIDTH, null );
  270               p.putClientProperty(BASICMENUITEMUI_MAX_TEXT_OFFSET, null );
  271           }
  272   
  273           menuItem = null;
  274       }
  275   
  276   
  277       protected void uninstallDefaults() {
  278           LookAndFeel.uninstallBorder(menuItem);
  279           LookAndFeel.installProperty(menuItem, "borderPainted", oldBorderPainted);
  280           if (menuItem.getMargin() instanceof UIResource)
  281               menuItem.setMargin(null);
  282           if (arrowIcon instanceof UIResource)
  283               arrowIcon = null;
  284           if (checkIcon instanceof UIResource)
  285               checkIcon = null;
  286       }
  287   
  288       /**
  289        * @since 1.3
  290        */
  291       protected void uninstallComponents(JMenuItem menuItem){
  292           BasicHTML.updateRenderer(menuItem, "");
  293       }
  294   
  295       protected void uninstallListeners() {
  296           if (mouseInputListener != null) {
  297               menuItem.removeMouseListener(mouseInputListener);
  298               menuItem.removeMouseMotionListener(mouseInputListener);
  299           }
  300           if (menuDragMouseListener != null) {
  301               menuItem.removeMenuDragMouseListener(menuDragMouseListener);
  302           }
  303           if (menuKeyListener != null) {
  304               menuItem.removeMenuKeyListener(menuKeyListener);
  305           }
  306           if (propertyChangeListener != null) {
  307               menuItem.removePropertyChangeListener(propertyChangeListener);
  308           }
  309   
  310           mouseInputListener = null;
  311           menuDragMouseListener = null;
  312           menuKeyListener = null;
  313           propertyChangeListener = null;
  314           handler = null;
  315       }
  316   
  317       protected void uninstallKeyboardActions() {
  318           SwingUtilities.replaceUIActionMap(menuItem, null);
  319           SwingUtilities.replaceUIInputMap(menuItem, JComponent.
  320                                            WHEN_IN_FOCUSED_WINDOW, null);
  321       }
  322   
  323       protected MouseInputListener createMouseInputListener(JComponent c) {
  324           return getHandler();
  325       }
  326   
  327       protected MenuDragMouseListener createMenuDragMouseListener(JComponent c) {
  328           return getHandler();
  329       }
  330   
  331       protected MenuKeyListener createMenuKeyListener(JComponent c) {
  332           return null;
  333       }
  334   
  335       /**
  336        * Creates a <code>PropertyChangeListener</code> which will be added to
  337        * the menu item.
  338        * If this method returns null then it will not be added to the menu item.
  339        *
  340        * @return an instance of a <code>PropertyChangeListener</code> or null
  341        * @since 1.6
  342        */
  343       protected PropertyChangeListener
  344                                     createPropertyChangeListener(JComponent c) {
  345           return getHandler();
  346       }
  347   
  348       Handler getHandler() {
  349           if (handler == null) {
  350               handler = new Handler();
  351           }
  352           return handler;
  353       }
  354   
  355       InputMap createInputMap(int condition) {
  356           if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
  357               return new ComponentInputMapUIResource(menuItem);
  358           }
  359           return null;
  360       }
  361   
  362       void updateAcceleratorBinding() {
  363           KeyStroke accelerator = menuItem.getAccelerator();
  364           InputMap windowInputMap = SwingUtilities.getUIInputMap(
  365                          menuItem, JComponent.WHEN_IN_FOCUSED_WINDOW);
  366   
  367           if (windowInputMap != null) {
  368               windowInputMap.clear();
  369           }
  370           if (accelerator != null) {
  371               if (windowInputMap == null) {
  372                   windowInputMap = createInputMap(JComponent.
  373                                                   WHEN_IN_FOCUSED_WINDOW);
  374                   SwingUtilities.replaceUIInputMap(menuItem,
  375                              JComponent.WHEN_IN_FOCUSED_WINDOW, windowInputMap);
  376               }
  377               windowInputMap.put(accelerator, "doClick");
  378           }
  379       }
  380   
  381       public Dimension getMinimumSize(JComponent c) {
  382           Dimension d = null;
  383           View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  384           if (v != null) {
  385               d = getPreferredSize(c);
  386               d.width -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS);
  387           }
  388           return d;
  389       }
  390   
  391       public Dimension getPreferredSize(JComponent c) {
  392           return getPreferredMenuItemSize(c,
  393                                           checkIcon,
  394                                           arrowIcon,
  395                                           defaultTextIconGap);
  396       }
  397   
  398       public Dimension getMaximumSize(JComponent c) {
  399           Dimension d = null;
  400           View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  401           if (v != null) {
  402               d = getPreferredSize(c);
  403               d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS);
  404           }
  405           return d;
  406       }
  407   
  408       // Returns parent of this component if it is not a top-level menu
  409       // Otherwise returns null
  410       private static JComponent getMenuItemParent(JMenuItem mi) {
  411           Container parent = mi.getParent();
  412           if ((parent instanceof JComponent) &&
  413                (!(mi instanceof JMenu) ||
  414                  !((JMenu)mi).isTopLevelMenu())) {
  415               return (JComponent) parent;
  416           } else {
  417               return null;
  418           }
  419       }
  420   
  421       protected Dimension getPreferredMenuItemSize(JComponent c,
  422                                                    Icon checkIcon,
  423                                                    Icon arrowIcon,
  424                                                    int defaultTextIconGap) {
  425   
  426           // The method also determines the preferred width of the
  427           // parent popup menu (through DefaultMenuLayout class).
  428           // The menu width equals to the maximal width
  429           // among child menu items.
  430   
  431           // Menu item width will be a sum of the widest check icon, label,
  432           // arrow icon and accelerator text among neighbor menu items.
  433           // For the latest menu item we will know the maximal widths exactly.
  434           // It will be the widest menu item and it will determine
  435           // the width of the parent popup menu.
  436   
  437           // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  438           // There is a conceptual problem: if user sets preferred size manually
  439           // for a menu item, this method won't be called for it
  440           // (see JComponent.getPreferredSize()),
  441           // maximal widths won't be calculated, other menu items won't be able
  442           // to take them into account and will be layouted in such a way,
  443           // as there is no the item with manual preferred size.
  444           // But after the first paint() method call, all maximal widths
  445           // will be correctly calculated and layout of some menu items
  446           // can be changed. For example, it can cause a shift of
  447           // the icon and text when user points a menu item by mouse.
  448   
  449           JMenuItem mi = (JMenuItem) c;
  450           LayoutInfo li = getLayoutInfo(mi, checkIcon, arrowIcon,
  451                   createMaxViewRect(), defaultTextIconGap, acceleratorDelimiter,
  452                   BasicGraphicsUtils.isLeftToRight(mi), acceleratorFont,
  453                   useCheckAndArrow(), getPropertyPrefix());
  454   
  455           Dimension result = new Dimension();
  456   
  457           // Calculate the result width
  458           result.width = li.leadingGap;
  459           addWidth(li.maxCheckWidth, li.afterCheckIconGap, result);
  460           // Take into account mimimal text offset.
  461           if ((!li.isTopLevelMenu)
  462                   && (li.minTextOffset > 0)
  463                   && (result.width < li.minTextOffset)) {
  464               result.width = li.minTextOffset;
  465           }
  466           addWidth(li.maxLabelWidth, li.gap, result);
  467           addWidth(li.maxAccWidth, li.gap, result);
  468           addWidth(li.maxArrowWidth, li.gap, result);
  469   
  470           // Calculate the result height
  471           result.height = max(li.checkRect.height, li.labelRect.height,
  472                               li.accRect.height, li.arrowRect.height);
  473   
  474           // Take into account menu item insets
  475           Insets insets = li.mi.getInsets();
  476           if(insets != null) {
  477               result.width += insets.left + insets.right;
  478               result.height += insets.top + insets.bottom;
  479           }
  480   
  481           // if the width is even, bump it up one. This is critical
  482           // for the focus dash line to draw properly
  483           if(result.width%2 == 0) {
  484               result.width++;
  485           }
  486   
  487           // if the height is even, bump it up one. This is critical
  488           // for the text to center properly
  489           if(result.height%2 == 0
  490                   && Boolean.TRUE !=
  491                       UIManager.get(getPropertyPrefix() + ".evenHeight")) {
  492               result.height++;
  493           }
  494   
  495           li.clear();
  496           return result;
  497       }
  498   
  499       private Rectangle createMaxViewRect() {
  500           return new Rectangle(0,0,Short.MAX_VALUE, Short.MAX_VALUE);
  501       }
  502   
  503       private void addWidth(int width, int gap, Dimension result) {
  504           if (width > 0) {
  505               result.width += width + gap;
  506           }
  507       }
  508   
  509       private static int max(int... values) {
  510           int maxValue = Integer.MIN_VALUE;
  511           for (int i : values) {
  512               if (i > maxValue) {
  513                   maxValue = i;
  514               }
  515           }
  516           return maxValue;
  517       }
  518   
  519       // LayoutInfo helps to calculate preferred size and to paint a menu item
  520       private static class LayoutInfo {
  521           JMenuItem mi;
  522           JComponent miParent;
  523   
  524           FontMetrics fm;
  525           FontMetrics accFm;
  526   
  527           Icon icon;
  528           Icon checkIcon;
  529           Icon arrowIcon;
  530           String text;
  531           String accText;
  532   
  533           boolean isColumnLayout;
  534           boolean useCheckAndArrow;
  535           boolean isLeftToRight;
  536           boolean isTopLevelMenu;
  537           View htmlView;
  538   
  539           int verticalAlignment;
  540           int horizontalAlignment;
  541           int verticalTextPosition;
  542           int horizontalTextPosition;
  543           int gap;
  544           int leadingGap;
  545           int afterCheckIconGap;
  546           int minTextOffset;
  547   
  548           Rectangle viewRect;
  549           Rectangle iconRect;
  550           Rectangle textRect;
  551           Rectangle accRect;
  552           Rectangle checkRect;
  553           Rectangle arrowRect;
  554           Rectangle labelRect;
  555   
  556           int origIconWidth;
  557           int origTextWidth;
  558           int origAccWidth;
  559           int origCheckWidth;
  560           int origArrowWidth;
  561   
  562           int maxIconWidth;
  563           int maxTextWidth;
  564           int maxAccWidth;
  565           int maxCheckWidth;
  566           int maxArrowWidth;
  567           int maxLabelWidth;
  568   
  569           // Empty constructor helps to create "final" LayoutInfo object
  570           public LayoutInfo() {
  571           }
  572   
  573           public LayoutInfo(JMenuItem mi, Icon checkIcon, Icon arrowIcon,
  574                             Rectangle viewRect, int gap, String accDelimiter,
  575                             boolean isLeftToRight, Font acceleratorFont,
  576                             boolean useCheckAndArrow, String propertyPrefix) {
  577               reset(mi, checkIcon, arrowIcon, viewRect, gap, accDelimiter,
  578                     isLeftToRight, acceleratorFont, useCheckAndArrow,
  579                     propertyPrefix);
  580           }
  581   
  582           // Allows to reuse a LayoutInfo object
  583           public void reset(JMenuItem mi, Icon checkIcon, Icon arrowIcon,
  584                             Rectangle viewRect, int gap, String accDelimiter,
  585                             boolean isLeftToRight, Font acceleratorFont,
  586                             boolean useCheckAndArrow, String propertyPrefix) {
  587               this.mi = mi;
  588               this.miParent = getMenuItemParent(mi);
  589               this.accText = getAccText(accDelimiter);
  590               this.verticalAlignment = mi.getVerticalAlignment();
  591               this.horizontalAlignment = mi.getHorizontalAlignment();
  592               this.verticalTextPosition = mi.getVerticalTextPosition();
  593               this.horizontalTextPosition = mi.getHorizontalTextPosition();
  594               this.useCheckAndArrow = useCheckAndArrow;
  595               this.fm = mi.getFontMetrics(mi.getFont());
  596               this.accFm = mi.getFontMetrics(acceleratorFont);
  597               this.isLeftToRight = isLeftToRight;
  598               this.isColumnLayout = isColumnLayout();
  599               this.isTopLevelMenu = (this.miParent == null)? true : false;
  600               this.checkIcon = checkIcon;
  601               this.icon = getIcon(propertyPrefix);
  602               this.arrowIcon = arrowIcon;
  603               this.text = mi.getText();
  604               this.gap = gap;
  605               this.afterCheckIconGap = getAfterCheckIconGap(propertyPrefix);
  606               this.minTextOffset = getMinTextOffset(propertyPrefix);
  607               this.htmlView = (View) mi.getClientProperty(BasicHTML.propertyKey);
  608   
  609               this.viewRect = viewRect;
  610               this.iconRect = new Rectangle();
  611               this.textRect = new Rectangle();
  612               this.accRect = new Rectangle();
  613               this.checkRect = new Rectangle();
  614               this.arrowRect = new Rectangle();
  615               this.labelRect = new Rectangle();
  616   
  617               calcWidthsAndHeights();
  618               this.origIconWidth = iconRect.width;
  619               this.origTextWidth = textRect.width;
  620               this.origAccWidth = accRect.width;
  621               this.origCheckWidth = checkRect.width;
  622               this.origArrowWidth = arrowRect.width;
  623   
  624               calcMaxWidths();
  625               this.leadingGap = getLeadingGap(propertyPrefix);
  626               calcMaxTextOffset();
  627           }
  628   
  629           // Clears fields to remove all links to other objects
  630           // to prevent memory leaks
  631           public void clear() {
  632               mi = null;
  633               miParent = null;
  634               fm = null;
  635               accFm = null;
  636               icon = null;
  637               checkIcon = null;
  638               arrowIcon = null;
  639               text = null;
  640               accText = null;
  641               htmlView = null;
  642               viewRect = null;
  643               iconRect = null;
  644               textRect = null;
  645               accRect = null;
  646               checkRect = null;
  647               arrowRect = null;
  648               labelRect = null;
  649           }
  650   
  651           private String getAccText(String acceleratorDelimiter) {
  652               String accText = "";
  653               KeyStroke accelerator = mi.getAccelerator();
  654               if (accelerator != null) {
  655                   int modifiers = accelerator.getModifiers();
  656                   if (modifiers > 0) {
  657                       accText = KeyEvent.getKeyModifiersText(modifiers);
  658                       accText += acceleratorDelimiter;
  659                   }
  660                   int keyCode = accelerator.getKeyCode();
  661                   if (keyCode != 0) {
  662                       accText += KeyEvent.getKeyText(keyCode);
  663                   } else {
  664                       accText += accelerator.getKeyChar();
  665                   }
  666               }
  667               return accText;
  668           }
  669   
  670           // In case of column layout, .checkIconFactory is defined for this UI,
  671           // the icon is compatible with it and useCheckAndArrow() is true,
  672           // then the icon is handled by the checkIcon.
  673           private Icon getIcon(String propertyPrefix) {
  674               Icon icon = null;
  675               MenuItemCheckIconFactory iconFactory =
  676                   (MenuItemCheckIconFactory) UIManager.get(propertyPrefix
  677                       + ".checkIconFactory");
  678               if (!isColumnLayout || !useCheckAndArrow || iconFactory == null
  679                       || !iconFactory.isCompatible(checkIcon, propertyPrefix)) {
  680                  icon = mi.getIcon();
  681               }
  682               return icon;
  683           }
  684   
  685           private int getMinTextOffset(String propertyPrefix) {
  686               int minimumTextOffset = 0;
  687               Object minimumTextOffsetObject =
  688                       UIManager.get(propertyPrefix + ".minimumTextOffset");
  689               if (minimumTextOffsetObject instanceof Integer) {
  690                   minimumTextOffset = (Integer) minimumTextOffsetObject;
  691               }
  692               return minimumTextOffset;
  693           }
  694   
  695           private int getAfterCheckIconGap(String propertyPrefix) {
  696               int afterCheckIconGap = gap;
  697               Object afterCheckIconGapObject =
  698                       UIManager.get(propertyPrefix + ".afterCheckIconGap");
  699               if (afterCheckIconGapObject instanceof Integer) {
  700                   afterCheckIconGap = (Integer) afterCheckIconGapObject;
  701               }
  702               return afterCheckIconGap;
  703           }
  704   
  705           private int getLeadingGap(String propertyPrefix) {
  706               if (maxCheckWidth > 0) {
  707                   return getCheckOffset(propertyPrefix);
  708               } else {
  709                   return gap; // There is no any check icon
  710               }
  711           }
  712   
  713           private int getCheckOffset(String propertyPrefix) {
  714               int checkIconOffset = gap;
  715               Object checkIconOffsetObject =
  716                       UIManager.get(propertyPrefix + ".checkIconOffset");
  717               if (checkIconOffsetObject instanceof Integer) {
  718                   checkIconOffset = (Integer) checkIconOffsetObject;
  719               }
  720               return checkIconOffset;
  721           }
  722   
  723           private void calcWidthsAndHeights()
  724           {
  725               // iconRect
  726               if (icon != null) {
  727                   iconRect.width = icon.getIconWidth();
  728                   iconRect.height = icon.getIconHeight();
  729               }
  730   
  731               // accRect
  732               if (!accText.equals("")) {
  733                   accRect.width = SwingUtilities2.stringWidth(
  734                           mi, accFm, accText);
  735                   accRect.height = accFm.getHeight();
  736               }
  737   
  738               // textRect
  739               if (text == null) {
  740                   text = "";
  741               } else if (!text.equals("")) {
  742                   if (htmlView != null) {
  743                       // Text is HTML
  744                       textRect.width =
  745                               (int) htmlView.getPreferredSpan(View.X_AXIS);
  746                       textRect.height =
  747                               (int) htmlView.getPreferredSpan(View.Y_AXIS);
  748                   } else {
  749                       // Text isn't HTML
  750                       textRect.width =
  751                               SwingUtilities2.stringWidth(mi, fm, text);
  752                       textRect.height = fm.getHeight();
  753                   }
  754               }
  755   
  756               if (useCheckAndArrow) {
  757                   // checkIcon
  758                   if (checkIcon != null) {
  759                       checkRect.width = checkIcon.getIconWidth();
  760                       checkRect.height = checkIcon.getIconHeight();
  761                   }
  762                   // arrowRect
  763                   if (arrowIcon != null) {
  764                       arrowRect.width = arrowIcon.getIconWidth();
  765                       arrowRect.height = arrowIcon.getIconHeight();
  766                   }
  767               }
  768   
  769               // labelRect
  770               if (isColumnLayout) {
  771                   labelRect.width = iconRect.width + textRect.width + gap;
  772                   labelRect.height = max(checkRect.height, iconRect.height,
  773                           textRect.height, accRect.height, arrowRect.height);
  774               } else {
  775                   textRect = new Rectangle();
  776                   iconRect = new Rectangle();
  777                   SwingUtilities.layoutCompoundLabel(mi, fm, text, icon,
  778                           verticalAlignment, horizontalAlignment,
  779                           verticalTextPosition, horizontalTextPosition,
  780                           viewRect, iconRect, textRect, gap);
  781                    labelRect = iconRect.union(textRect);
  782               }
  783           }
  784   
  785           private void calcMaxWidths() {
  786               maxCheckWidth = calcMaxValue(BasicMenuItemUI.MAX_CHECK_WIDTH,
  787                       checkRect.width);
  788               maxArrowWidth = calcMaxValue(BasicMenuItemUI.MAX_ARROW_WIDTH,
  789                       arrowRect.width);
  790               maxAccWidth = calcMaxValue(BasicMenuItemUI.MAX_ACC_WIDTH,
  791                       accRect.width);
  792   
  793               if (isColumnLayout) {
  794                   maxIconWidth = calcMaxValue(BasicMenuItemUI.MAX_ICON_WIDTH,
  795                           iconRect.width);
  796                   maxTextWidth = calcMaxValue(BasicMenuItemUI.MAX_TEXT_WIDTH,
  797                           textRect.width);
  798                   int curGap = gap;
  799                   if ((maxIconWidth == 0) || (maxTextWidth == 0)) {
  800                       curGap = 0;
  801                   }
  802                   maxLabelWidth =
  803                           calcMaxValue(BasicMenuItemUI.MAX_LABEL_WIDTH,
  804                           maxIconWidth + maxTextWidth + curGap);
  805               } else {
  806                   // We shouldn't use current icon and text widths
  807                   // in maximal widths calculation for complex layout.
  808                   maxIconWidth = getParentIntProperty(BasicMenuItemUI.MAX_ICON_WIDTH);
  809                   maxLabelWidth = calcMaxValue(BasicMenuItemUI.MAX_LABEL_WIDTH,
  810                           labelRect.width);
  811                   // If maxLabelWidth is wider
  812                   // than the widest icon + the widest text + gap,
  813                   // we should update the maximal text witdh
  814                   int candidateTextWidth = maxLabelWidth - maxIconWidth;
  815                   if (maxIconWidth > 0) {
  816                       candidateTextWidth -= gap;
  817                   }
  818                   maxTextWidth = calcMaxValue(BasicMenuItemUI.MAX_TEXT_WIDTH,
  819                           candidateTextWidth);
  820               }
  821           }
  822   
  823           // Calculates and returns maximal value
  824           // through specified parent component client property.
  825           private int calcMaxValue(Object propertyName, int value) {
  826               // Get maximal value from parent client property
  827               int maxValue = getParentIntProperty(propertyName);
  828               // Store new maximal width in parent client property
  829               if (value > maxValue) {
  830                   if (miParent != null) {
  831                       miParent.putClientProperty(propertyName, value);
  832                   }
  833                   return value;
  834               } else {
  835                   return maxValue;
  836               }
  837           }
  838   
  839           // Returns parent client property as int
  840           private int getParentIntProperty(Object propertyName) {
  841               Object value = null;
  842               if (miParent != null) {
  843                   value = miParent.getClientProperty(propertyName);
  844               }
  845               if ((value == null) || !(value instanceof Integer)){
  846                   value = 0;
  847               }
  848               return (Integer)value;
  849           }
  850   
  851           private boolean isColumnLayout() {
  852               return isColumnLayout(isLeftToRight, horizontalAlignment,
  853                       horizontalTextPosition, verticalTextPosition);
  854           }
  855   
  856           public static boolean isColumnLayout(boolean isLeftToRight,
  857                                                JMenuItem mi) {
  858               assert(mi != null);
  859               return isColumnLayout(isLeftToRight, mi.getHorizontalAlignment(),
  860                       mi.getHorizontalTextPosition(), mi.getVerticalTextPosition());
  861           }
  862   
  863           // Answers should we do column layout for a menu item or not.
  864           // We do it when a user doesn't set any alignments
  865           // and text positions manually, except the vertical alignment.
  866           public static boolean isColumnLayout( boolean isLeftToRight,
  867                   int horizontalAlignment, int horizontalTextPosition,
  868                   int verticalTextPosition) {
  869               if (verticalTextPosition != SwingConstants.CENTER) {
  870                   return false;
  871               }
  872               if (isLeftToRight) {
  873                   if (horizontalAlignment != SwingConstants.LEADING
  874                    && horizontalAlignment != SwingConstants.LEFT) {
  875                       return false;
  876                   }
  877                   if (horizontalTextPosition != SwingConstants.TRAILING
  878                    && horizontalTextPosition != SwingConstants.RIGHT) {
  879                       return false;
  880                   }
  881               } else {
  882                   if (horizontalAlignment != SwingConstants.LEADING
  883                    && horizontalAlignment != SwingConstants.RIGHT) {
  884                       return false;
  885                   }
  886                   if (horizontalTextPosition != SwingConstants.TRAILING
  887                    && horizontalTextPosition != SwingConstants.LEFT) {
  888                       return false;
  889                   }
  890               }
  891               return true;
  892           }
  893   
  894           // Calculates maximal text offset.
  895           // It is required for some L&Fs (ex: Vista L&F).
  896           // The offset is meaningful only for L2R column layout.
  897           private void calcMaxTextOffset() {
  898               if (!isColumnLayout || !isLeftToRight) {
  899                   return;
  900               }
  901   
  902               // Calculate the current text offset
  903               int offset = viewRect.x + leadingGap + maxCheckWidth
  904                        + afterCheckIconGap + maxIconWidth + gap;
  905               if (maxCheckWidth == 0) {
  906                   offset -= afterCheckIconGap;
  907               }
  908               if (maxIconWidth == 0) {
  909                   offset -= gap;
  910               }
  911   
  912               // maximal text offset shouldn't be less than minimal text offset;
  913               if (offset < minTextOffset) {
  914                   offset = minTextOffset;
  915               }
  916   
  917               // Calculate and store the maximal text offset
  918               calcMaxValue(BASICMENUITEMUI_MAX_TEXT_OFFSET, offset);
  919           }
  920   
  921           public String toString() {
  922               StringBuilder result = new StringBuilder();
  923               result.append(super.toString()).append("\n");
  924               result.append("accFm = ").append(accFm).append("\n");
  925               result.append("accRect = ").append(accRect).append("\n");
  926               result.append("accText = ").append(accText).append("\n");
  927               result.append("afterCheckIconGap = ").append(afterCheckIconGap)
  928                       .append("\n");
  929               result.append("arrowIcon = ").append(arrowIcon).append("\n");
  930               result.append("arrowRect = ").append(arrowRect).append("\n");
  931               result.append("checkIcon = ").append(checkIcon).append("\n");
  932               result.append("checkRect = ").append(checkRect).append("\n");
  933               result.append("fm = ").append(fm).append("\n");
  934               result.append("gap = ").append(gap).append("\n");
  935               result.append("horizontalAlignment = ").append(horizontalAlignment)
  936                       .append("\n");
  937               result.append("horizontalTextPosition = ")
  938                       .append(horizontalTextPosition).append("\n");
  939               result.append("htmlView = ").append(htmlView).append("\n");
  940               result.append("icon = ").append(icon).append("\n");
  941               result.append("iconRect = ").append(iconRect).append("\n");
  942               result.append("isColumnLayout = ").append(isColumnLayout).append("\n");
  943               result.append("isLeftToRight = ").append(isLeftToRight).append("\n");
  944               result.append("isTopLevelMenu = ").append(isTopLevelMenu).append("\n");
  945               result.append("labelRect = ").append(labelRect).append("\n");
  946               result.append("leadingGap = ").append(leadingGap).append("\n");
  947               result.append("maxAccWidth = ").append(maxAccWidth).append("\n");
  948               result.append("maxArrowWidth = ").append(maxArrowWidth).append("\n");
  949               result.append("maxCheckWidth = ").append(maxCheckWidth).append("\n");
  950               result.append("maxIconWidth = ").append(maxIconWidth).append("\n");
  951               result.append("maxLabelWidth = ").append(maxLabelWidth).append("\n");
  952               result.append("maxTextWidth = ").append(maxTextWidth).append("\n");
  953               result.append("maxTextOffset = ")
  954                       .append(getParentIntProperty(BASICMENUITEMUI_MAX_TEXT_OFFSET))
  955                       .append("\n");
  956               result.append("mi = ").append(mi).append("\n");
  957               result.append("minTextOffset = ").append(minTextOffset).append("\n");
  958               result.append("miParent = ").append(miParent).append("\n");
  959               result.append("origAccWidth = ").append(origAccWidth).append("\n");
  960               result.append("origArrowWidth = ").append(origArrowWidth).append("\n");
  961               result.append("origCheckWidth = ").append(origCheckWidth).append("\n");
  962               result.append("origIconWidth = ").append(origIconWidth).append("\n");
  963               result.append("origTextWidth = ").append(origTextWidth).append("\n");
  964               result.append("text = ").append(text).append("\n");
  965               result.append("textRect = ").append(textRect).append("\n");
  966               result.append("useCheckAndArrow = ").append(useCheckAndArrow)
  967                       .append("\n");
  968               result.append("verticalAlignment = ").append(verticalAlignment)
  969                       .append("\n");
  970               result.append("verticalTextPosition = ")
  971                       .append(verticalTextPosition).append("\n");
  972               result.append("viewRect = ").append(viewRect).append("\n");
  973               return result.toString();
  974           }
  975       } // End of LayoutInfo
  976   
  977       // Reuses layoutInfo object to reduce the amount of produced garbage
  978       private LayoutInfo getLayoutInfo(JMenuItem mi, Icon checkIcon, Icon arrowIcon,
  979                                Rectangle viewRect, int gap, String accDelimiter,
  980                                boolean isLeftToRight, Font acceleratorFont,
  981                                boolean useCheckAndArrow, String propertyPrefix) {
  982           // layoutInfo is final and always not null
  983           layoutInfo.reset(mi, checkIcon, arrowIcon, viewRect,
  984                   gap, accDelimiter, isLeftToRight, acceleratorFont,
  985                   useCheckAndArrow, propertyPrefix);
  986           return layoutInfo;
  987       }
  988   
  989       /**
  990        * We draw the background in paintMenuItem()
  991        * so override update (which fills the background of opaque
  992        * components by default) to just call paint().
  993        *
  994        */
  995       public void update(Graphics g, JComponent c) {
  996           paint(g, c);
  997       }
  998   
  999       public void paint(Graphics g, JComponent c) {
 1000           paintMenuItem(g, c, checkIcon, arrowIcon,
 1001                         selectionBackground, selectionForeground,
 1002                         defaultTextIconGap);
 1003       }
 1004   
 1005       protected void paintMenuItem(Graphics g, JComponent c,
 1006                                        Icon checkIcon, Icon arrowIcon,
 1007                                        Color background, Color foreground,
 1008                                        int defaultTextIconGap) {
 1009           // Save original graphics font and color
 1010           Font holdf = g.getFont();
 1011           Color holdc = g.getColor();
 1012   
 1013           JMenuItem mi = (JMenuItem) c;
 1014           g.setFont(mi.getFont());
 1015   
 1016           Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight());
 1017           applyInsets(viewRect, mi.getInsets());
 1018   
 1019           LayoutInfo li = getLayoutInfo(mi, checkIcon, arrowIcon,
 1020                   viewRect, defaultTextIconGap, acceleratorDelimiter,
 1021                   BasicGraphicsUtils.isLeftToRight(mi), acceleratorFont,
 1022                   useCheckAndArrow(), getPropertyPrefix());
 1023           layoutMenuItem(li);
 1024   
 1025           paintBackground(g, mi, background);
 1026           paintCheckIcon(g, li, holdc, foreground);
 1027           paintIcon(g, li, holdc);
 1028           paintText(g, li);
 1029           paintAccText(g, li);
 1030           paintArrowIcon(g, li, foreground);
 1031   
 1032           // Restore original graphics font and color
 1033           g.setColor(holdc);
 1034           g.setFont(holdf);
 1035   
 1036           li.clear();
 1037       }
 1038   
 1039       private void paintIcon(Graphics g, LayoutInfo li, Color holdc) {
 1040           if (li.icon != null) {
 1041               Icon icon;
 1042               ButtonModel model = li.mi.getModel();
 1043               if (!model.isEnabled()) {
 1044                   icon = (Icon) li.mi.getDisabledIcon();
 1045               } else if (model.isPressed() && model.isArmed()) {
 1046                   icon = (Icon) li.mi.getPressedIcon();
 1047                   if (icon == null) {
 1048                       // Use default icon
 1049                       icon = (Icon) li.mi.getIcon();
 1050                   }
 1051               } else {
 1052                   icon = (Icon) li.mi.getIcon();
 1053               }
 1054   
 1055               if (icon != null) {
 1056                   icon.paintIcon(li.mi, g, li.iconRect.x, li.iconRect.y);
 1057                   g.setColor(holdc);
 1058               }
 1059           }
 1060       }
 1061   
 1062       private void paintCheckIcon(Graphics g, LayoutInfo li,
 1063                                   Color holdc, Color foreground) {
 1064           if (li.checkIcon != null) {
 1065               ButtonModel model = li.mi.getModel();
 1066               if (model.isArmed()
 1067                       || (li.mi instanceof JMenu && model.isSelected())) {
 1068                   g.setColor(foreground);
 1069               } else {
 1070                   g.setColor(holdc);
 1071               }
 1072               if (li.useCheckAndArrow) {
 1073                   li.checkIcon.paintIcon(li.mi, g, li.checkRect.x,
 1074                                          li.checkRect.y);
 1075               }
 1076               g.setColor(holdc);
 1077           }
 1078       }
 1079   
 1080       private void paintAccText(Graphics g, LayoutInfo li) {
 1081           if (!li.accText.equals("")) {
 1082               ButtonModel model = li.mi.getModel();
 1083               g.setFont(acceleratorFont);
 1084               if (!model.isEnabled()) {
 1085                   // *** paint the accText disabled
 1086                   if (disabledForeground != null) {
 1087                       g.setColor(disabledForeground);
 1088                       SwingUtilities2.drawString(li.mi, g, li.accText,
 1089                                    li.accRect.x,
 1090                                    li.accRect.y + li.accFm.getAscent());
 1091                   } else {
 1092                       g.setColor(li.mi.getBackground().brighter());
 1093                       SwingUtilities2.drawString(li.mi, g, li.accText, li.accRect.x,
 1094                                    li.accRect.y + li.accFm.getAscent());
 1095                       g.setColor(li.mi.getBackground().darker());
 1096                       SwingUtilities2.drawString(li.mi, g, li.accText,
 1097                               li.accRect.x - 1,
 1098                               li.accRect.y + li.accFm.getAscent() - 1);
 1099                   }
 1100               } else {
 1101                   // *** paint the accText normally
 1102                   if (model.isArmed() ||
 1103                           (li.mi instanceof JMenu && model.isSelected())) {
 1104                       g.setColor(acceleratorSelectionForeground);
 1105                   } else {
 1106                       g.setColor(acceleratorForeground);
 1107                   }
 1108                   SwingUtilities2.drawString(li.mi, g, li.accText, li.accRect.x,
 1109                           li.accRect.y + li.accFm.getAscent());
 1110               }
 1111           }
 1112       }
 1113   
 1114       private void paintText(Graphics g, LayoutInfo li) {
 1115           if (!li.text.equals("")) {
 1116               if (li.htmlView != null) {
 1117                   // Text is HTML
 1118                   li.htmlView.paint(g, li.textRect);
 1119               } else {
 1120                   // Text isn't HTML
 1121                   paintText(g, li.mi, li.textRect, li.text);
 1122               }
 1123           }
 1124       }
 1125   
 1126       private void paintArrowIcon(Graphics g, LayoutInfo li, Color foreground) {
 1127           if (li.arrowIcon != null) {
 1128               ButtonModel model = li.mi.getModel();
 1129               if (model.isArmed()
 1130                       || (li.mi instanceof JMenu && model.isSelected())) {
 1131                   g.setColor(foreground);
 1132               }
 1133               if (li.useCheckAndArrow) {
 1134                   li.arrowIcon.paintIcon(li.mi, g, li.arrowRect.x, li.arrowRect.y);
 1135               }
 1136           }
 1137       }
 1138   
 1139       private void applyInsets(Rectangle rect, Insets insets) {
 1140           if(insets != null) {
 1141               rect.x += insets.left;
 1142               rect.y += insets.top;
 1143               rect.width -= (insets.right + rect.x);
 1144               rect.height -= (insets.bottom + rect.y);
 1145           }
 1146       }
 1147   
 1148       /**
 1149        * Draws the background of the menu item.
 1150        *
 1151        * @param g the paint graphics
 1152        * @param menuItem menu item to be painted
 1153        * @param bgColor selection background color
 1154        * @since 1.4
 1155        */
 1156       protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) {
 1157           ButtonModel model = menuItem.getModel();
 1158           Color oldColor = g.getColor();
 1159           int menuWidth = menuItem.getWidth();
 1160           int menuHeight = menuItem.getHeight();
 1161   
 1162           if(menuItem.isOpaque()) {
 1163               if (model.isArmed()|| (menuItem instanceof JMenu && model.isSelected())) {
 1164                   g.setColor(bgColor);
 1165                   g.fillRect(0,0, menuWidth, menuHeight);
 1166               } else {
 1167                   g.setColor(menuItem.getBackground());
 1168                   g.fillRect(0,0, menuWidth, menuHeight);
 1169               }
 1170               g.setColor(oldColor);
 1171           }
 1172           else if (model.isArmed() || (menuItem instanceof JMenu &&
 1173                                        model.isSelected())) {
 1174               g.setColor(bgColor);
 1175               g.fillRect(0,0, menuWidth, menuHeight);
 1176               g.setColor(oldColor);
 1177           }
 1178       }
 1179   
 1180       /**
 1181        * Renders the text of the current menu item.
 1182        * <p>
 1183        * @param g graphics context
 1184        * @param menuItem menu item to render
 1185        * @param textRect bounding rectangle for rendering the text
 1186        * @param text string to render
 1187        * @since 1.4
 1188        */
 1189       protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) {
 1190           ButtonModel model = menuItem.getModel();
 1191           FontMetrics fm = SwingUtilities2.getFontMetrics(menuItem, g);
 1192           int mnemIndex = menuItem.getDisplayedMnemonicIndex();
 1193   
 1194           if(!model.isEnabled()) {
 1195               // *** paint the text disabled
 1196               if ( UIManager.get("MenuItem.disabledForeground") instanceof Color ) {
 1197                   g.setColor( UIManager.getColor("MenuItem.disabledForeground") );
 1198                   SwingUtilities2.drawStringUnderlineCharAt(menuItem, g,text,
 1199                             mnemIndex, textRect.x,  textRect.y + fm.getAscent());
 1200               } else {
 1201                   g.setColor(menuItem.getBackground().brighter());
 1202                   SwingUtilities2.drawStringUnderlineCharAt(menuItem, g, text,
 1203                              mnemIndex, textRect.x, textRect.y + fm.getAscent());
 1204                   g.setColor(menuItem.getBackground().darker());
 1205                   SwingUtilities2.drawStringUnderlineCharAt(menuItem, g,text,
 1206                              mnemIndex,  textRect.x - 1, textRect.y +
 1207                              fm.getAscent() - 1);
 1208               }
 1209           } else {
 1210               // *** paint the text normally
 1211               if (model.isArmed()|| (menuItem instanceof JMenu && model.isSelected())) {
 1212                   g.setColor(selectionForeground); // Uses protected field.
 1213               }
 1214               SwingUtilities2.drawStringUnderlineCharAt(menuItem, g,text,
 1215                              mnemIndex, textRect.x, textRect.y + fm.getAscent());
 1216           }
 1217       }
 1218   
 1219   
 1220       /**
 1221        * Layout icon, text, check icon, accelerator text and arrow icon
 1222        * in the viewRect and return their positions.
 1223        *
 1224        * If horizontalAlignment, verticalTextPosition and horizontalTextPosition
 1225        * are default (user doesn't set any manually) the layouting algorithm is:
 1226        * Elements are layouted in the five columns:
 1227        * check icon + icon + text + accelerator text + arrow icon
 1228        *
 1229        * In the other case elements are layouted in the four columns:
 1230        * check icon + label + accelerator text + arrow icon
 1231        * Label is icon and text rectangles union.
 1232        *
 1233        * The order of columns can be reversed.
 1234        * It depends on the menu item orientation.
 1235        */
 1236       private void layoutMenuItem(LayoutInfo li)
 1237       {
 1238           li.checkRect.width = li.maxCheckWidth;
 1239           li.accRect.width = li.maxAccWidth;
 1240           li.arrowRect.width = li.maxArrowWidth;
 1241   
 1242           if (li.isColumnLayout) {
 1243               if (li.isLeftToRight) {
 1244                   doLTRColumnLayout(li);
 1245               } else {
 1246                   doRTLColumnLayout(li);
 1247               }
 1248           } else {
 1249               if (li.isLeftToRight) {
 1250                   doLTRComplexLayout(li);
 1251               } else {
 1252                   doRTLComplexLayout(li);
 1253               }
 1254           }
 1255   
 1256           alignAccCheckAndArrowVertically(li);
 1257       }
 1258   
 1259       // Aligns the accelertor text and the check and arrow icons vertically
 1260       // with the center of the label rect.
 1261       private void alignAccCheckAndArrowVertically(LayoutInfo li) {
 1262           li.accRect.y = (int)(li.labelRect.y + (float)li.labelRect.height/2
 1263                   - (float)li.accRect.height/2);
 1264           fixVerticalAlignment(li, li.accRect);
 1265           if (li.useCheckAndArrow) {
 1266               li.arrowRect.y = (int)(li.labelRect.y + (float)li.labelRect.height/2
 1267                       - (float)li.arrowRect.height/2);
 1268               li.checkRect.y = (int)(li.labelRect.y + (float)li.labelRect.height/2
 1269                       - (float)li.checkRect.height/2);
 1270               fixVerticalAlignment(li, li.arrowRect);
 1271               fixVerticalAlignment(li, li.checkRect);
 1272           }
 1273       }
 1274   
 1275       // Fixes vertical alignment of all menu item elements if a rect.y
 1276       // or (rect.y + rect.height) is out of viewRect bounds
 1277       private void fixVerticalAlignment(LayoutInfo li, Rectangle r) {
 1278           int delta = 0;
 1279           if (r.y < li.viewRect.y) {
 1280               delta = li.viewRect.y - r.y;
 1281           } else if (r.y + r.height > li.viewRect.y + li.viewRect.height) {
 1282               delta = li.viewRect.y + li.viewRect.height - r.y - r.height;
 1283           }
 1284           if (delta != 0) {
 1285               li.checkRect.y += delta;
 1286               li.iconRect.y += delta;
 1287               li.textRect.y += delta;
 1288               li.accRect.y += delta;
 1289               li.arrowRect.y += delta;
 1290           }
 1291       }
 1292   
 1293       private void doLTRColumnLayout(LayoutInfo li) {
 1294           // Set maximal width for all the five basic rects
 1295           // (three other ones are already maximal)
 1296           li.iconRect.width = li.maxIconWidth;
 1297           li.textRect.width = li.maxTextWidth;
 1298   
 1299           // Set X coordinates
 1300           // All rects will be aligned at the left side
 1301           calcXPositionsL2R(li.viewRect.x, li.leadingGap, li.gap, li.checkRect,
 1302                   li.iconRect, li.textRect);
 1303   
 1304           // Tune afterCheckIconGap
 1305           if (li.checkRect.width > 0) { // there is the afterCheckIconGap
 1306               li.iconRect.x += li.afterCheckIconGap - li.gap;
 1307               li.textRect.x += li.afterCheckIconGap - li.gap;
 1308           }
 1309   
 1310           calcXPositionsR2L(li.viewRect.x + li.viewRect.width, li.gap,
 1311                   li.arrowRect, li.accRect);
 1312   
 1313           // Take into account minimal text offset
 1314           int textOffset = li.textRect.x - li.viewRect.x;
 1315           if (!li.isTopLevelMenu && (textOffset < li.minTextOffset)) {
 1316               li.textRect.x += li.minTextOffset - textOffset;
 1317           }
 1318   
 1319           // Take into account the left side bearings for text and accelerator text.
 1320           fixTextRects(li);
 1321   
 1322           // Set Y coordinate for text and icon.
 1323           // Y coordinates for other rects
 1324           // will be calculated later in layoutMenuItem.
 1325           calcTextAndIconYPositions(li);
 1326   
 1327           // Calculate valid X and Y coordinates for labelRect
 1328           li.labelRect = li.textRect.union(li.iconRect);
 1329       }
 1330   
 1331       private void doLTRComplexLayout(LayoutInfo li) {
 1332           li.labelRect.width = li.maxLabelWidth;
 1333   
 1334           // Set X coordinates
 1335           calcXPositionsL2R(li.viewRect.x, li.leadingGap, li.gap, li.checkRect,
 1336                   li.labelRect);
 1337   
 1338           // Tune afterCheckIconGap
 1339           if (li.checkRect.width > 0) { // there is the afterCheckIconGap
 1340               li.labelRect.x += li.afterCheckIconGap - li.gap;
 1341           }
 1342   
 1343           calcXPositionsR2L(li.viewRect.x + li.viewRect.width, li.gap,
 1344                   li.arrowRect, li.accRect);
 1345   
 1346           // Take into account minimal text offset
 1347           int labelOffset = li.labelRect.x - li.viewRect.x;
 1348           if (!li.isTopLevelMenu && (labelOffset < li.minTextOffset)) {
 1349               li.labelRect.x += li.minTextOffset - labelOffset;
 1350           }
 1351   
 1352           // Take into account the left side bearing for accelerator text.
 1353           // The LSB for text is taken into account in layoutCompoundLabel() below.
 1354           fixAccTextRect(li);
 1355   
 1356           // Layout icon and text with SwingUtilities.layoutCompoundLabel()
 1357           // within the labelRect
 1358           li.textRect = new Rectangle();
 1359           li.iconRect = new Rectangle();
 1360           SwingUtilities.layoutCompoundLabel(
 1361                               li.mi, li.fm, li.text, li.icon, li.verticalAlignment,
 1362                               li.horizontalAlignment, li.verticalTextPosition,
 1363                               li.horizontalTextPosition, li.labelRect,
 1364                               li.iconRect, li.textRect, li.gap);
 1365       }
 1366   
 1367       private void doRTLColumnLayout(LayoutInfo li) {
 1368           // Set maximal width for all the five basic rects
 1369           // (three other ones are already maximal)
 1370           li.iconRect.width = li.maxIconWidth;
 1371           li.textRect.width = li.maxTextWidth;
 1372   
 1373           // Set X coordinates
 1374           calcXPositionsR2L(li.viewRect.x + li.viewRect.width, li.leadingGap,
 1375                   li.gap, li.checkRect, li.iconRect, li.textRect);
 1376   
 1377           // Tune the gap after check icon
 1378           if (li.checkRect.width > 0) { // there is the gap after check icon
 1379               li.iconRect.x -= li.afterCheckIconGap - li.gap;
 1380               li.textRect.x -= li.afterCheckIconGap - li.gap;
 1381           }
 1382   
 1383           calcXPositionsL2R(li.viewRect.x, li.gap, li.arrowRect,
 1384                   li.accRect);
 1385   
 1386           // Take into account minimal text offset
 1387           int textOffset = (li.viewRect.x + li.viewRect.width)
 1388                          - (li.textRect.x + li.textRect.width);
 1389           if (!li.isTopLevelMenu && (textOffset < li.minTextOffset)) {
 1390               li.textRect.x -= li.minTextOffset - textOffset;
 1391           }
 1392   
 1393           // Align icon, text, accelerator text, check icon and arrow icon
 1394           // at the right side
 1395           rightAlignAllRects(li);
 1396   
 1397           // Take into account the left side bearings for text and accelerator text.
 1398           fixTextRects(li);
 1399   
 1400           // Set Y coordinates for text and icon.
 1401           // Y coordinates for other rects
 1402           // will be calculated later in layoutMenuItem.
 1403           calcTextAndIconYPositions(li);
 1404   
 1405           // Calculate valid X and Y coordinate for labelRect
 1406           li.labelRect = li.textRect.union(li.iconRect);
 1407       }
 1408   
 1409       private void doRTLComplexLayout(LayoutInfo li) {
 1410           li.labelRect.width = li.maxLabelWidth;
 1411   
 1412           // Set X coordinates
 1413           calcXPositionsR2L(li.viewRect.x + li.viewRect.width, li.leadingGap,
 1414                   li.gap, li.checkRect, li.labelRect);
 1415   
 1416           // Tune the gap after check icon
 1417           if (li.checkRect.width > 0) { // there is the gap after check icon
 1418               li.labelRect.x -= li.afterCheckIconGap - li.gap;
 1419           }
 1420   
 1421           calcXPositionsL2R(li.viewRect.x, li.gap, li.arrowRect,
 1422                   li.accRect);
 1423   
 1424           // Take into account minimal text offset
 1425           int labelOffset = (li.viewRect.x + li.viewRect.width)
 1426                           - (li.labelRect.x + li.labelRect.width);
 1427           if (!li.isTopLevelMenu && (labelOffset < li.minTextOffset)) {
 1428               li.labelRect.x -= li.minTextOffset - labelOffset;
 1429           }
 1430   
 1431           // Align icon, text, accelerator text, check icon and arrow icon
 1432           // at the right side
 1433           rightAlignAllRects(li);
 1434   
 1435           // Take into account the left side bearing for accelerator text.
 1436           // The LSB for text is taken into account in layoutCompoundLabel() below.
 1437           fixAccTextRect(li);
 1438   
 1439           // Layout icon and text with SwingUtilities.layoutCompoundLabel()
 1440           // within the labelRect
 1441           li.textRect = new Rectangle();
 1442           li.iconRect = new Rectangle();
 1443           SwingUtilities.layoutCompoundLabel(
 1444                               menuItem, li.fm, li.text, li.icon, li.verticalAlignment,
 1445                               li.horizontalAlignment, li.verticalTextPosition,
 1446                               li.horizontalTextPosition, li.labelRect,
 1447                               li.iconRect, li.textRect, li.gap);
 1448       }
 1449   
 1450       private void calcXPositionsL2R(int startXPos, int leadingGap,
 1451                                      int gap, Rectangle... rects) {
 1452           int curXPos = startXPos + leadingGap;
 1453           for (Rectangle rect : rects) {
 1454               rect.x = curXPos;
 1455               if (rect.width > 0) {
 1456                   curXPos += rect.width + gap;
 1457               }
 1458           }
 1459       }
 1460   
 1461       private void calcXPositionsL2R(int startXPos, int gap, Rectangle... rects) {
 1462           calcXPositionsL2R(startXPos, gap, gap, rects);
 1463       }
 1464   
 1465       private void calcXPositionsR2L(int startXPos, int leadingGap,
 1466                                      int gap, Rectangle... rects) {
 1467           int curXPos = startXPos - leadingGap;
 1468           for (Rectangle rect : rects) {
 1469               rect.x = curXPos - rect.width;
 1470               if (rect.width > 0) {
 1471                   curXPos -= rect.width + gap;
 1472               }
 1473           }
 1474       }
 1475   
 1476       private void calcXPositionsR2L(int startXPos, int gap, Rectangle... rects) {
 1477           calcXPositionsR2L(startXPos, gap, gap, rects);
 1478       }
 1479   
 1480       // Takes into account the left side bearings for text and accelerator text
 1481       private void fixTextRects(LayoutInfo li) {
 1482           if (li.htmlView == null) { // The text isn't a HTML
 1483               int lsb = SwingUtilities2.getLeftSideBearing(li.mi, li.fm, li.text);
 1484               if (lsb < 0) {
 1485                   li.textRect.x -= lsb;
 1486               }
 1487           }
 1488           fixAccTextRect(li);
 1489       }
 1490   
 1491       // Takes into account the left side bearing for accelerator text
 1492       private void fixAccTextRect(LayoutInfo li) {
 1493           int lsb = SwingUtilities2
 1494                   .getLeftSideBearing(li.mi, li.accFm, li.accText);
 1495           if (lsb < 0) {
 1496               li.accRect.x -= lsb;
 1497           }
 1498       }
 1499   
 1500       // Sets Y coordinates of text and icon
 1501       // taking into account the vertical alignment
 1502       private void calcTextAndIconYPositions(LayoutInfo li) {
 1503           if (li.verticalAlignment == SwingUtilities.TOP) {
 1504               li.textRect.y  = (int)(li.viewRect.y
 1505                       + (float)li.labelRect.height/2
 1506                       - (float)li.textRect.height/2);
 1507               li.iconRect.y  = (int)(li.viewRect.y
 1508                       + (float)li.labelRect.height/2
 1509                       - (float)li.iconRect.height/2);
 1510           } else if (li.verticalAlignment == SwingUtilities.CENTER) {
 1511               li.textRect.y = (int)(li.viewRect.y
 1512                       + (float)li.viewRect.height/2
 1513                       - (float)li.textRect.height/2);
 1514               li.iconRect.y = (int)(li.viewRect.y
 1515                       + (float)li.viewRect.height/2
 1516                       - (float)li.iconRect.height/2);
 1517           }
 1518           else if (li.verticalAlignment == SwingUtilities.BOTTOM) {
 1519               li.textRect.y = (int)(li.viewRect.y + li.viewRect.height
 1520                       - (float)li.labelRect.height/2
 1521                       - (float)li.textRect.height/2);
 1522               li.iconRect.y = (int)(li.viewRect.y + li.viewRect.height
 1523                       - (float)li.labelRect.height/2
 1524                       - (float)li.iconRect.height/2);
 1525           }
 1526       }
 1527   
 1528       // Aligns icon, text, accelerator text, check icon and arrow icon
 1529       // at the right side
 1530       private void rightAlignAllRects(LayoutInfo li) {
 1531           li.iconRect.x = li.iconRect.x + li.iconRect.width - li.origIconWidth;
 1532           li.iconRect.width = li.origIconWidth;
 1533           li.textRect.x = li.textRect.x + li.textRect.width - li.origTextWidth;
 1534           li.textRect.width = li.origTextWidth;
 1535           li.accRect.x = li.accRect.x + li.accRect.width
 1536                   - li.origAccWidth;
 1537           li.accRect.width = li.origAccWidth;
 1538           li.checkRect.x = li.checkRect.x + li.checkRect.width
 1539                   - li.origCheckWidth;
 1540           li.checkRect.width = li.origCheckWidth;
 1541           li.arrowRect.x = li.arrowRect.x + li.arrowRect.width -
 1542                   li.origArrowWidth;
 1543           li.arrowRect.width = li.origArrowWidth;
 1544       }
 1545   
 1546       /*
 1547        * Returns false if the component is a JMenu and it is a top
 1548        * level menu (on the menubar).
 1549        */
 1550       private boolean useCheckAndArrow(){
 1551           boolean b = true;
 1552           if((menuItem instanceof JMenu) &&
 1553              (((JMenu)menuItem).isTopLevelMenu())) {
 1554               b = false;
 1555           }
 1556           return b;
 1557       }
 1558   
 1559       public MenuElement[] getPath() {
 1560           MenuSelectionManager m = MenuSelectionManager.defaultManager();
 1561           MenuElement oldPath[] = m.getSelectedPath();
 1562           MenuElement newPath[];
 1563           int i = oldPath.length;
 1564           if (i == 0)
 1565               return new MenuElement[0];
 1566           Component parent = menuItem.getParent();
 1567           if (oldPath[i-1].getComponent() == parent) {
 1568               // The parent popup menu is the last so far
 1569               newPath = new MenuElement[i+1];
 1570               System.arraycopy(oldPath, 0, newPath, 0, i);
 1571               newPath[i] = menuItem;
 1572           } else {
 1573               // A sibling menuitem is the current selection
 1574               //
 1575               //  This probably needs to handle 'exit submenu into
 1576               // a menu item.  Search backwards along the current
 1577               // selection until you find the parent popup menu,
 1578               // then copy up to that and add yourself...
 1579               int j;
 1580               for (j = oldPath.length-1; j >= 0; j--) {
 1581                   if (oldPath[j].getComponent() == parent)
 1582                       break;
 1583               }
 1584               newPath = new MenuElement[j+2];
 1585               System.arraycopy(oldPath, 0, newPath, 0, j+1);
 1586               newPath[j+1] = menuItem;
 1587               /*
 1588               System.out.println("Sibling condition -- ");
 1589               System.out.println("Old array : ");
 1590               printMenuElementArray(oldPath, false);
 1591               System.out.println("New array : ");
 1592               printMenuElementArray(newPath, false);
 1593               */
 1594           }
 1595           return newPath;
 1596       }
 1597   
 1598       void printMenuElementArray(MenuElement path[], boolean dumpStack) {
 1599           System.out.println("Path is(");
 1600           int i, j;
 1601           for(i=0,j=path.length; i<j ;i++){
 1602               for (int k=0; k<=i; k++)
 1603                   System.out.print("  ");
 1604               MenuElement me = (MenuElement) path[i];
 1605               if(me instanceof JMenuItem)
 1606                   System.out.println(((JMenuItem)me).getText() + ", ");
 1607               else if (me == null)
 1608                   System.out.println("NULL , ");
 1609               else
 1610                   System.out.println("" + me + ", ");
 1611           }
 1612           System.out.println(")");
 1613   
 1614           if (dumpStack == true)
 1615               Thread.dumpStack();
 1616       }
 1617       protected class MouseInputHandler implements MouseInputListener {
 1618           // NOTE: This class exists only for backward compatability. All
 1619           // its functionality has been moved into Handler. If you need to add
 1620           // new functionality add it to the Handler, but make sure this
 1621           // class calls into the Handler.
 1622   
 1623           public void mouseClicked(MouseEvent e) {
 1624               getHandler().mouseClicked(e);
 1625           }
 1626           public void mousePressed(MouseEvent e) {
 1627               getHandler().mousePressed(e);
 1628           }
 1629           public void mouseReleased(MouseEvent e) {
 1630               getHandler().mouseReleased(e);
 1631           }
 1632           public void mouseEntered(MouseEvent e) {
 1633               getHandler().mouseEntered(e);
 1634           }
 1635           public void mouseExited(MouseEvent e) {
 1636               getHandler().mouseExited(e);
 1637           }
 1638           public void mouseDragged(MouseEvent e) {
 1639               getHandler().mouseDragged(e);
 1640           }
 1641           public void mouseMoved(MouseEvent e) {
 1642               getHandler().mouseMoved(e);
 1643           }
 1644       }
 1645   
 1646   
 1647       private static class Actions extends UIAction {
 1648           private static final String CLICK = "doClick";
 1649   
 1650           Actions(String key) {
 1651               super(key);
 1652           }
 1653   
 1654           public void actionPerformed(ActionEvent e) {
 1655               JMenuItem mi = (JMenuItem)e.getSource();
 1656               MenuSelectionManager.defaultManager().clearSelectedPath();
 1657               mi.doClick();
 1658           }
 1659       }
 1660   
 1661       /**
 1662        * Call this method when a menu item is to be activated.
 1663        * This method handles some of the details of menu item activation
 1664        * such as clearing the selected path and messaging the
 1665        * JMenuItem's doClick() method.
 1666        *
 1667        * @param msm  A MenuSelectionManager. The visual feedback and
 1668        *             internal bookkeeping tasks are delegated to
 1669        *             this MenuSelectionManager. If <code>null</code> is
 1670        *             passed as this argument, the
 1671        *             <code>MenuSelectionManager.defaultManager</code> is
 1672        *             used.
 1673        * @see MenuSelectionManager
 1674        * @see JMenuItem#doClick(int)
 1675        * @since 1.4
 1676        */
 1677       protected void doClick(MenuSelectionManager msm) {
 1678           // Auditory cue
 1679           if (! isInternalFrameSystemMenu()) {
 1680               BasicLookAndFeel.playSound(menuItem, getPropertyPrefix() +
 1681                                          ".commandSound");
 1682           }
 1683           // Visual feedback
 1684           if (msm == null) {
 1685               msm = MenuSelectionManager.defaultManager();
 1686           }
 1687           msm.clearSelectedPath();
 1688           menuItem.doClick(0);
 1689       }
 1690   
 1691       /**
 1692        * This is to see if the menu item in question is part of the
 1693        * system menu on an internal frame.
 1694        * The Strings that are being checked can be found in
 1695        * MetalInternalFrameTitlePaneUI.java,
 1696        * WindowsInternalFrameTitlePaneUI.java, and
 1697        * MotifInternalFrameTitlePaneUI.java.
 1698        *
 1699        * @since 1.4
 1700        */
 1701       private boolean isInternalFrameSystemMenu() {
 1702           String actionCommand = menuItem.getActionCommand();
 1703           if ((actionCommand == "Close") ||
 1704               (actionCommand == "Minimize") ||
 1705               (actionCommand == "Restore") ||
 1706               (actionCommand == "Maximize")) {
 1707             return true;
 1708           } else {
 1709             return false;
 1710           }
 1711       }
 1712   
 1713   
 1714       // BasicMenuUI subclasses this.
 1715       class Handler implements MenuDragMouseListener,
 1716                             MouseInputListener, PropertyChangeListener {
 1717           //
 1718           // MouseInputListener
 1719           //
 1720           public void mouseClicked(MouseEvent e) {}
 1721           public void mousePressed(MouseEvent e) {
 1722           }
 1723           public void mouseReleased(MouseEvent e) {
 1724               if (!menuItem.isEnabled()) {
 1725                   return;
 1726               }
 1727               MenuSelectionManager manager =
 1728                   MenuSelectionManager.defaultManager();
 1729               Point p = e.getPoint();
 1730               if(p.x >= 0 && p.x < menuItem.getWidth() &&
 1731                  p.y >= 0 && p.y < menuItem.getHeight()) {
 1732                   doClick(manager);
 1733               } else {
 1734                   manager.processMouseEvent(e);
 1735               }
 1736           }
 1737           public void mouseEntered(MouseEvent e) {
 1738               MenuSelectionManager manager = MenuSelectionManager.defaultManager();
 1739               int modifiers = e.getModifiers();
 1740               // 4188027: drag enter/exit added in JDK 1.1.7A, JDK1.2
 1741               if ((modifiers & (InputEvent.BUTTON1_MASK |
 1742                                 InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK)) !=0 ) {
 1743                   MenuSelectionManager.defaultManager().processMouseEvent(e);
 1744               } else {
 1745               manager.setSelectedPath(getPath());
 1746                }
 1747           }
 1748           public void mouseExited(MouseEvent e) {
 1749               MenuSelectionManager manager = MenuSelectionManager.defaultManager();
 1750   
 1751               int modifiers = e.getModifiers();
 1752               // 4188027: drag enter/exit added in JDK 1.1.7A, JDK1.2
 1753               if ((modifiers & (InputEvent.BUTTON1_MASK |
 1754                                 InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK)) !=0 ) {
 1755                   MenuSelectionManager.defaultManager().processMouseEvent(e);
 1756               } else {
 1757   
 1758                   MenuElement path[] = manager.getSelectedPath();
 1759                   if (path.length > 1 && path[path.length-1] == menuItem) {
 1760                       MenuElement newPath[] = new MenuElement[path.length-1];
 1761                       int i,c;
 1762                       for(i=0,c=path.length-1;i<c;i++)
 1763                           newPath[i] = path[i];
 1764                       manager.setSelectedPath(newPath);
 1765                   }
 1766                   }
 1767           }
 1768   
 1769           public void mouseDragged(MouseEvent e) {
 1770               MenuSelectionManager.defaultManager().processMouseEvent(e);
 1771           }
 1772           public void mouseMoved(MouseEvent e) {
 1773           }
 1774   
 1775           //
 1776           // MenuDragListener
 1777           //
 1778           public void menuDragMouseEntered(MenuDragMouseEvent e) {
 1779               MenuSelectionManager manager = e.getMenuSelectionManager();
 1780               MenuElement path[] = e.getPath();
 1781               manager.setSelectedPath(path);
 1782           }
 1783           public void menuDragMouseDragged(MenuDragMouseEvent e) {
 1784               MenuSelectionManager manager = e.getMenuSelectionManager();
 1785               MenuElement path[] = e.getPath();
 1786               manager.setSelectedPath(path);
 1787           }
 1788           public void menuDragMouseExited(MenuDragMouseEvent e) {}
 1789           public void menuDragMouseReleased(MenuDragMouseEvent e) {
 1790               if (!menuItem.isEnabled()) {
 1791                   return;
 1792               }
 1793               MenuSelectionManager manager = e.getMenuSelectionManager();
 1794               MenuElement path[] = e.getPath();
 1795               Point p = e.getPoint();
 1796               if (p.x >= 0 && p.x < menuItem.getWidth() &&
 1797                       p.y >= 0 && p.y < menuItem.getHeight()) {
 1798                   doClick(manager);
 1799               } else {
 1800                   manager.clearSelectedPath();
 1801               }
 1802           }
 1803   
 1804   
 1805           //
 1806           // PropertyChangeListener
 1807           //
 1808           public void propertyChange(PropertyChangeEvent e) {
 1809               String name = e.getPropertyName();
 1810   
 1811               if (name == "labelFor" || name == "displayedMnemonic" ||
 1812                   name == "accelerator") {
 1813                   updateAcceleratorBinding();
 1814               } else if (name == "text" || "font" == name ||
 1815                          "foreground" == name) {
 1816                   // remove the old html view client property if one
 1817                   // existed, and install a new one if the text installed
 1818                   // into the JLabel is html source.
 1819                   JMenuItem lbl = ((JMenuItem) e.getSource());
 1820                   String text = lbl.getText();
 1821                   BasicHTML.updateRenderer(lbl, text);
 1822               } else if (name  == "iconTextGap") {
 1823                   defaultTextIconGap = ((Number)e.getNewValue()).intValue();
 1824               }
 1825           }
 1826       }
 1827   }

Save This Page
Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]