KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jgoodies > looks > common > MenuItemRenderer


1 /*
2  * Copyright (c) 2001-2005 JGoodies Karsten Lentzsch. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * o Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  *
10  * o Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * o Neither the name of JGoodies Karsten Lentzsch nor the names of
15  * its contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31 package com.jgoodies.looks.common;
32
33 import java.awt.*;
34 import java.awt.event.KeyEvent JavaDoc;
35
36 import javax.swing.*;
37 import javax.swing.plaf.basic.BasicGraphicsUtils JavaDoc;
38 import javax.swing.plaf.basic.BasicHTML JavaDoc;
39 import javax.swing.text.View JavaDoc;
40
41 import com.jgoodies.looks.Options;
42
43 /**
44  * Renders and lays out menu items.
45  *
46  * @author Karsten Lentzsch
47  * @version $Revision: 1.4 $
48  */

49
50 public final class MenuItemRenderer {
51
52     /*
53      * Implementation note: The protected visibility prevents
54      * the String value from being encrypted by the obfuscator.
55      * An encrypted String key would break the client property lookup
56      * in the #paint method below.
57      */

58     protected static final String JavaDoc HTML_KEY = BasicHTML.propertyKey;
59
60     /* Client Property keys for text and accelerator text widths */
61     private static final String JavaDoc MAX_TEXT_WIDTH = "maxTextWidth";
62     private static final String JavaDoc MAX_ACC_WIDTH = "maxAccWidth";
63
64     private static final Icon NO_ICON = new NullIcon();
65     
66     
67     static Rectangle zeroRect = new Rectangle(0,0,0,0);
68     static Rectangle iconRect = new Rectangle();
69     static Rectangle textRect = new Rectangle();
70     static Rectangle acceleratorRect= new Rectangle();
71     static Rectangle checkIconRect = new Rectangle();
72     static Rectangle arrowIconRect = new Rectangle();
73     static Rectangle viewRect = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE);
74     static Rectangle r = new Rectangle();
75
76
77     private final JMenuItem menuItem;
78     private final boolean iconBorderEnabled; // when selected or pressed.
79
private final Font acceleratorFont;
80     private final Color selectionForeground;
81     private final Color disabledForeground;
82     private final Color acceleratorForeground;
83     private final Color acceleratorSelectionForeground;
84     
85     private final String JavaDoc acceleratorDelimiter;
86     private final Icon fillerIcon;
87     
88     
89     
90     /**
91      * Constructs a MenuItemRenderer for the specified menu item and settings.
92      */

93     public MenuItemRenderer(JMenuItem menuItem, boolean iconBorderEnabled,
94         Font acceleratorFont,
95         Color selectionForeground,
96         Color disabledForeground,
97         Color acceleratorForeground,
98         Color acceleratorSelectionForeground) {
99         this.menuItem = menuItem;
100         this.iconBorderEnabled = iconBorderEnabled;
101         this.acceleratorFont = acceleratorFont;
102         this.selectionForeground = selectionForeground;
103         this.disabledForeground = disabledForeground;
104         this.acceleratorForeground = acceleratorForeground;
105         this.acceleratorSelectionForeground = acceleratorSelectionForeground;
106         this.acceleratorDelimiter = UIManager.getString("MenuItem.acceleratorDelimiter");
107         this.fillerIcon = new MinimumSizedIcon();
108     }
109     
110     
111     /**
112      * Looks up and answers the appropriate menu item icon.
113      */

114     private Icon getIcon(JMenuItem aMenuItem, Icon defaultIcon) {
115         Icon icon = aMenuItem.getIcon();
116         if (icon == null)
117             return defaultIcon;
118             
119         ButtonModel model = aMenuItem.getModel();
120         if (!model.isEnabled()) {
121             return model.isSelected()
122                         ? aMenuItem.getDisabledSelectedIcon()
123                         : aMenuItem.getDisabledIcon();
124         } else if (model.isPressed() && model.isArmed()) {
125             Icon pressedIcon = aMenuItem.getPressedIcon();
126             return pressedIcon != null ? pressedIcon : icon;
127         } else if (model.isSelected()) {
128             Icon selectedIcon = aMenuItem.getSelectedIcon();
129             return selectedIcon != null ? selectedIcon : icon;
130         } else
131             return icon;
132     }
133     
134     
135     /**
136      * Checks and answers if the menu item has a custom icon.
137      */

138     private boolean hasCustomIcon() {
139         return getIcon(menuItem, null) != null;
140     }
141
142
143     /**
144      * Answers the wrapped icon.
145      */

146     private Icon getWrappedIcon(Icon icon) {
147         if (hideIcons())
148             return NO_ICON;
149         if (icon == null)
150             return fillerIcon;
151         return iconBorderEnabled && hasCustomIcon()
152             ? new MinimumSizedCheckIcon(icon, menuItem)
153             : new MinimumSizedIcon(icon);
154     }
155     
156     
157     private void resetRects() {
158         iconRect.setBounds(zeroRect);
159         textRect.setBounds(zeroRect);
160         acceleratorRect.setBounds(zeroRect);
161         checkIconRect.setBounds(zeroRect);
162         arrowIconRect.setBounds(zeroRect);
163         viewRect.setBounds(0, 0, Short.MAX_VALUE, Short.MAX_VALUE);
164         r.setBounds(zeroRect);
165     }
166     
167
168     public Dimension getPreferredMenuItemSize(JComponent c,
169         Icon checkIcon, Icon arrowIcon, int defaultTextIconGap) {
170             
171         JMenuItem b = (JMenuItem) c;
172         String JavaDoc text = b.getText();
173         KeyStroke accelerator = b.getAccelerator();
174         String JavaDoc acceleratorText = "";
175
176         if (accelerator != null) {
177             int modifiers = accelerator.getModifiers();
178             if (modifiers > 0) {
179                 acceleratorText = KeyEvent.getKeyModifiersText(modifiers);
180                 acceleratorText += acceleratorDelimiter;
181             }
182             int keyCode = accelerator.getKeyCode();
183             if (keyCode != 0) {
184                 acceleratorText += KeyEvent.getKeyText(keyCode);
185             } else {
186                 acceleratorText += accelerator.getKeyChar();
187             }
188         }
189
190         Font font = b.getFont();
191         FontMetrics fm = b.getFontMetrics(font);
192         FontMetrics fmAccel = b.getFontMetrics(acceleratorFont);
193
194         resetRects();
195         
196         Icon wrappedIcon = getWrappedIcon(getIcon(menuItem, checkIcon));
197         Icon wrappedArrowIcon = getWrappedIcon(arrowIcon);
198         Icon icon = wrappedIcon.getIconHeight() > fillerIcon.getIconHeight()
199                     ? wrappedIcon
200                     : null;
201
202         layoutMenuItem(fm, text, fmAccel, acceleratorText,
203             //icon, checkIcon,
204
icon, wrappedIcon,
205             wrappedArrowIcon, //arrowIcon,
206
b.getVerticalAlignment(), b.getHorizontalAlignment(),
207             b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
208             viewRect, iconRect, textRect, acceleratorRect, checkIconRect, arrowIconRect,
209             text == null ? 0 : defaultTextIconGap,
210             defaultTextIconGap);
211         // find the union of the icon and text rects
212
r.setBounds(textRect);
213         r = SwingUtilities.computeUnion(iconRect.x, iconRect.y, iconRect.width, iconRect.height, r);
214         // r = iconRect.union(textRect);
215

216         // To make the accelerator texts appear in a column, find the widest MenuItem text
217
// and the widest accelerator text.
218

219         //Get the parent, which stores the information.
220
Container parent = menuItem.getParent();
221
222         //Check the parent, and see that it is not a top-level menu.
223
if (parent != null
224             && parent instanceof JComponent
225             && !(menuItem instanceof JMenu && ((JMenu) menuItem).isTopLevelMenu())) {
226             JComponent p = (JComponent) parent;
227
228             //Get widest text so far from parent, if no one exists null is returned.
229
Integer JavaDoc maxTextWidth = (Integer JavaDoc) p.getClientProperty(MAX_TEXT_WIDTH);
230             Integer JavaDoc maxAccWidth = (Integer JavaDoc) p.getClientProperty(MAX_ACC_WIDTH);
231
232             int maxTextValue = maxTextWidth != null ? maxTextWidth.intValue() : 0;
233             int maxAccValue = maxAccWidth != null ? maxAccWidth.intValue() : 0;
234
235             //Compare the text widths, and adjust the r.width to the widest.
236
if (r.width < maxTextValue) {
237                 r.width = maxTextValue;
238             } else {
239                 p.putClientProperty(MAX_TEXT_WIDTH, new Integer JavaDoc(r.width));
240             }
241
242             //Compare the accelarator widths.
243
if (acceleratorRect.width > maxAccValue) {
244                 maxAccValue = acceleratorRect.width;
245                 p.putClientProperty(MAX_ACC_WIDTH, new Integer JavaDoc(acceleratorRect.width));
246             }
247
248             //Add on the widest accelerator
249
r.width += maxAccValue;
250             r.width += 10;
251         }
252
253         if (useCheckAndArrow()) {
254             // Add in the checkIcon
255
r.width += checkIconRect.width;
256             r.width += defaultTextIconGap;
257
258             // Add in the arrowIcon
259
r.width += defaultTextIconGap;
260             r.width += arrowIconRect.width;
261         }
262
263         r.width += 2 * defaultTextIconGap;
264
265         Insets insets = b.getInsets();
266         if (insets != null) {
267             r.width += insets.left + insets.right;
268             r.height += insets.top + insets.bottom;
269         }
270
271         // if the width is even, bump it up one. This is critical
272
// for the focus dash line to draw properly
273
/* JGoodies: Can't believe the above
274          * if(r.width%2 == 0) {
275             r.width++;
276         }*/

277
278         // if the height is even, bump it up one. This is critical
279
// for the text to center properly
280
// JGoodies: An even height is critical to center icons properly
281
if(r.height % 2 == 1) {
282             r.height++;
283         }
284         return r.getSize();
285     }
286
287
288     public void paintMenuItem(Graphics g, JComponent c,
289         Icon checkIcon, Icon arrowIcon,
290         Color background, Color foreground, int defaultTextIconGap) {
291         JMenuItem b = (JMenuItem) c;
292         ButtonModel model = b.getModel();
293
294         // Dimension size = b.getSize();
295
int menuWidth = b.getWidth();
296         int menuHeight = b.getHeight();
297         Insets i = c.getInsets();
298
299         resetRects();
300
301         viewRect.setBounds(0, 0, menuWidth, menuHeight);
302
303         viewRect.x += i.left;
304         viewRect.y += i.top;
305         viewRect.width -= (i.right + viewRect.x);
306         viewRect.height -= (i.bottom + viewRect.y);
307
308         Font holdf = g.getFont();
309         Font f = c.getFont();
310         g.setFont(f);
311         FontMetrics fm = g.getFontMetrics(f);
312         FontMetrics fmAccel = g.getFontMetrics(acceleratorFont);
313
314         // get Accelerator text
315
KeyStroke accelerator = b.getAccelerator();
316         String JavaDoc acceleratorText = "";
317         if (accelerator != null) {
318             int modifiers = accelerator.getModifiers();
319             if (modifiers > 0) {
320                 acceleratorText = KeyEvent.getKeyModifiersText(modifiers);
321                 acceleratorText += acceleratorDelimiter;
322             }
323
324             int keyCode = accelerator.getKeyCode();
325             if (keyCode != 0) {
326                 acceleratorText += KeyEvent.getKeyText(keyCode);
327             } else {
328                 acceleratorText += accelerator.getKeyChar();
329             }
330         }
331
332         Icon wrappedIcon = getWrappedIcon(getIcon(menuItem, checkIcon));
333         Icon wrappedArrowIcon = new MinimumSizedIcon(arrowIcon);
334         
335         // layout the text and icon
336
String JavaDoc text = layoutMenuItem(fm, b.getText(), fmAccel, acceleratorText,
337                 // b.getIcon(), checkIcon,
338
null, wrappedIcon,
339                 wrappedArrowIcon, //arrowIcon,
340
b.getVerticalAlignment(), b.getHorizontalAlignment(),
341                 b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
342                 viewRect, iconRect, textRect, acceleratorRect, checkIconRect, arrowIconRect,
343                 b.getText() == null ? 0 : defaultTextIconGap,
344                 defaultTextIconGap);
345
346         // Paint background
347
paintBackground(g, b, background);
348
349         // Paint icon
350
Color holdc = g.getColor();
351         if (model.isArmed() || (c instanceof JMenu && model.isSelected())) {
352             g.setColor(foreground);
353         }
354         wrappedIcon.paintIcon(c, g, checkIconRect.x, checkIconRect.y);
355         g.setColor(holdc);
356
357
358         // Draw the Text
359
if (text != null) {
360             View JavaDoc v = (View JavaDoc) c.getClientProperty(HTML_KEY);
361             if (v != null) {
362                 v.paint(g, textRect);
363             } else {
364                 paintText(g, b, textRect, text);
365             }
366         }
367
368         // Draw the Accelerator Text
369
if (acceleratorText != null && !acceleratorText.equals("")) {
370
371             //Get the maxAccWidth from the parent to calculate the offset.
372
int accOffset = 0;
373             Container parent = menuItem.getParent();
374             if (parent != null && parent instanceof JComponent) {
375                 JComponent p = (JComponent) parent;
376                 Integer JavaDoc maxValueInt = (Integer JavaDoc) p.getClientProperty(MAX_ACC_WIDTH);
377                 int maxValue = maxValueInt != null ? maxValueInt.intValue() : acceleratorRect.width;
378
379                 //Calculate the offset, with which the accelerator texts will be drawn with.
380
accOffset = maxValue - acceleratorRect.width;
381             }
382
383             g.setFont(acceleratorFont);
384             if (!model.isEnabled()) {
385                 // *** paint the acceleratorText disabled
386
if (disabledForeground != null) {
387                     g.setColor(disabledForeground);
388                     BasicGraphicsUtils.drawString(g, acceleratorText, 0,
389                         acceleratorRect.x - accOffset,
390                         acceleratorRect.y + fmAccel.getAscent());
391                 } else {
392                     g.setColor(b.getBackground().brighter());
393                     BasicGraphicsUtils.drawString(g, acceleratorText, 0,
394                         acceleratorRect.x - accOffset,
395                         acceleratorRect.y + fmAccel.getAscent());
396                     g.setColor(b.getBackground().darker());
397                     BasicGraphicsUtils.drawString(g, acceleratorText, 0,
398                         acceleratorRect.x - accOffset - 1,
399                         acceleratorRect.y + fmAccel.getAscent() - 1);
400                 }
401             } else {
402                 // *** paint the acceleratorText normally
403
if (model.isArmed() || (c instanceof JMenu && model.isSelected())) {
404                     g.setColor(acceleratorSelectionForeground);
405                 } else {
406                     g.setColor(acceleratorForeground);
407                 }
408                 BasicGraphicsUtils.drawString(g, acceleratorText, 0,
409                     acceleratorRect.x - accOffset,
410                     acceleratorRect.y + fmAccel.getAscent());
411             }
412         }
413
414         // Paint the Arrow
415
if (arrowIcon != null) {
416             if (model.isArmed() || (c instanceof JMenu && model.isSelected()))
417                 g.setColor(foreground);
418             if (useCheckAndArrow())
419                 wrappedArrowIcon.paintIcon(c, g, arrowIconRect.x, arrowIconRect.y);
420         }
421         g.setColor(holdc);
422         g.setFont(holdf);
423     }
424
425     /**
426      * Compute and return the location of the icons origin, the
427      * location of origin of the text baseline, and a possibly clipped
428      * version of the compound labels string. Locations are computed
429      * relative to the viewRect rectangle.
430      */

431     private String JavaDoc layoutMenuItem(FontMetrics fm, String JavaDoc text,
432         FontMetrics fmAccel, String JavaDoc acceleratorText,
433         Icon icon, Icon checkIcon, Icon arrowIcon,
434         int verticalAlignment, int horizontalAlignment,
435         int verticalTextPosition, int horizontalTextPosition,
436         Rectangle viewRectangle,
437         Rectangle iconRectangle,
438         Rectangle textRectangle,
439         Rectangle acceleratorRectangle,
440         Rectangle checkIconRectangle,
441         Rectangle arrowIconRectangle,
442         int textIconGap,
443         int menuItemGap) {
444
445         SwingUtilities.layoutCompoundLabel(menuItem, fm, text, icon,
446             verticalAlignment, horizontalAlignment,
447             verticalTextPosition, horizontalTextPosition,
448             viewRectangle, iconRectangle, textRectangle, textIconGap);
449
450         /* Initialize the acceleratorText bounds rectangle textRect. If a null
451          * or and empty String was specified we substitute "" here
452          * and use 0,0,0,0 for acceleratorTextRect.
453          */

454         if ((acceleratorText == null) || acceleratorText.equals("")) {
455             acceleratorRectangle.width = acceleratorRectangle.height = 0;
456             acceleratorText = "";
457         } else {
458             acceleratorRectangle.width = SwingUtilities.computeStringWidth(fmAccel, acceleratorText);
459             acceleratorRectangle.height = fmAccel.getHeight();
460         }
461         
462         boolean useCheckAndArrow = useCheckAndArrow();
463
464         // Initialize the checkIcon bounds rectangle's width & height.
465

466         if (useCheckAndArrow) {
467             if (checkIcon != null) {
468                 checkIconRectangle.width = checkIcon.getIconWidth();
469                 checkIconRectangle.height = checkIcon.getIconHeight();
470             } else {
471                 checkIconRectangle.width = checkIconRectangle.height = 0;
472             }
473
474             // Initialize the arrowIcon bounds rectangle width & height.
475

476             if (arrowIcon != null) {
477                 arrowIconRectangle.width = arrowIcon.getIconWidth();
478                 arrowIconRectangle.height = arrowIcon.getIconHeight();
479             } else {
480                 arrowIconRectangle.width = arrowIconRectangle.height = 0;
481             }
482         }
483
484         Rectangle labelRect = iconRectangle.union(textRectangle);
485         if (isLeftToRight(menuItem)) {
486             textRectangle.x += menuItemGap;
487             iconRectangle.x += menuItemGap;
488
489             // Position the Accelerator text rect
490
acceleratorRectangle.x = viewRectangle.x
491                     + viewRectangle.width
492                     - arrowIconRectangle.width
493                     - menuItemGap
494                     - acceleratorRectangle.width;
495
496             // Position the Check and Arrow Icons
497
if (useCheckAndArrow) {
498                 checkIconRectangle.x = viewRectangle.x; // + menuItemGap; JGoodies: No leading gap
499
textRectangle.x += menuItemGap + checkIconRectangle.width;
500                 iconRectangle.x += menuItemGap + checkIconRectangle.width;
501                 arrowIconRectangle.x = viewRectangle.x + viewRectangle.width - menuItemGap - arrowIconRectangle.width;
502             }
503         } else {
504             textRectangle.x -= menuItemGap;
505             iconRectangle.x -= menuItemGap;
506
507             // Position the Accelerator text rect
508
acceleratorRectangle.x = viewRectangle.x + arrowIconRectangle.width + menuItemGap;
509
510             // Position the Check and Arrow Icons
511
if (useCheckAndArrow) {
512                 // JGoodies: No trailing gap
513
checkIconRectangle.x = viewRectangle.x + viewRectangle.width - checkIconRectangle.width;
514                 textRectangle.x -= menuItemGap + checkIconRectangle.width;
515                 iconRectangle.x -= menuItemGap + checkIconRectangle.width;
516                 arrowIconRectangle.x = viewRectangle.x + menuItemGap;
517             }
518         }
519
520         // Align the accelerator text and the check and arrow icons vertically
521
// with the center of the label rect.
522
acceleratorRectangle.y = labelRect.y + (labelRect.height / 2) - (acceleratorRectangle.height / 2);
523         if (useCheckAndArrow) {
524             arrowIconRectangle.y = labelRect.y + (labelRect.height / 2) - (arrowIconRectangle.height / 2);
525             checkIconRectangle.y = labelRect.y + (labelRect.height / 2) - (checkIconRectangle.height / 2);
526         }
527
528         /*
529         System.out.println("Layout: text="+menuItem.getText()+"\n\tv="
530                            +viewRect+"\n\tc="+checkIconRect+"\n\ti="
531                            +iconRect+"\n\tt="+textRect+"\n\tacc="
532                            +acceleratorRect+"\n\ta="+arrowIconRect+"\n");
533         */

534
535         return text;
536     }
537     
538     /*
539      * Returns false if the component is a JMenu and it is a top
540      * level menu (on the menubar).
541      */

542     private boolean useCheckAndArrow() {
543         boolean isTopLevelMenu = menuItem instanceof JMenu &&
544                                  ((JMenu) menuItem).isTopLevelMenu();
545         return !isTopLevelMenu;
546     }
547     
548     
549     private boolean isLeftToRight(Component c) {
550         return c.getComponentOrientation().isLeftToRight();
551     }
552     
553     
554     // Copies from 1.4.1 ****************************************************
555

556
557     /**
558      * Draws the background of the menu item.
559      * Copied from 1.4.1 BasicMenuItem to make it visible to the
560      * MenuItemLayouter
561      *
562      * @param g the paint graphics
563      * @param aMenuItem menu item to be painted
564      * @param bgColor selection background color
565      * @since 1.4
566      */

567     public void paintBackground(Graphics g, JMenuItem aMenuItem, Color bgColor) {
568         ButtonModel model = aMenuItem.getModel();
569         
570         if (aMenuItem.isOpaque()) {
571             int menuWidth = aMenuItem.getWidth();
572             int menuHeight = aMenuItem.getHeight();
573             Color c = model.isArmed() ||
574                      (aMenuItem instanceof JMenu && model.isSelected())
575                        ? bgColor
576                        : aMenuItem.getBackground();
577             Color oldColor = g.getColor();
578             g.setColor(c);
579             g.fillRect(0, 0, menuWidth, menuHeight);
580             g.setColor(oldColor);
581         }
582     }
583
584     
585     /**
586      * Renders the text of the current menu item.
587      * <p>
588      * @param g graphics context
589      * @param aMenuItem menu item to render
590      * @param textRectangle bounding rectangle for rendering the text
591      * @param text string to render
592      * @since 1.4
593      */

594     public void paintText(Graphics g, JMenuItem aMenuItem, Rectangle textRectangle, String JavaDoc text) {
595         ButtonModel model = aMenuItem.getModel();
596         FontMetrics fm = g.getFontMetrics();
597         int mnemIndex = aMenuItem.getDisplayedMnemonicIndex();
598     
599         if(!model.isEnabled()) {
600             // *** paint the text disabled
601
if ( UIManager.get("MenuItem.disabledForeground") instanceof Color ) {
602                 g.setColor( UIManager.getColor("MenuItem.disabledForeground") );
603                 BasicGraphicsUtils.drawStringUnderlineCharAt(g,text,mnemIndex,
604                                   textRectangle.x,
605                                   textRectangle.y + fm.getAscent());
606             } else {
607                 g.setColor(aMenuItem.getBackground().brighter());
608                 BasicGraphicsUtils.drawStringUnderlineCharAt(g,text,mnemIndex,
609                                   textRectangle.x,
610                                   textRectangle.y + fm.getAscent());
611                 g.setColor(aMenuItem.getBackground().darker());
612                 BasicGraphicsUtils.drawStringUnderlineCharAt(g,text,mnemIndex,
613                                   textRectangle.x - 1,
614                                   textRectangle.y + fm.getAscent() - 1);
615             }
616         } else {
617             // *** paint the text normally
618
if (model.isArmed()|| (aMenuItem instanceof JMenu && model.isSelected())) {
619                 g.setColor(selectionForeground); // Uses protected field.
620
}
621             BasicGraphicsUtils.drawStringUnderlineCharAt(g,text, mnemIndex,
622                           textRectangle.x,
623                           textRectangle.y + fm.getAscent());
624         }
625     }
626     
627     
628     // Private Helper Code *************************************************************
629

630     /**
631      * Checks and answers if the parent menu indicates that we should use no icons.
632      */

633     private boolean hideIcons() {
634         Component parent = menuItem.getParent();
635         if (!(parent instanceof JPopupMenu)) {
636             return false;
637         }
638         JPopupMenu popupMenu = (JPopupMenu) parent;
639         Object JavaDoc value = popupMenu.getClientProperty(Options.NO_ICONS_KEY);
640         if (value == null) {
641             Component invoker = popupMenu.getInvoker();
642             if (invoker != null && invoker instanceof JMenu)
643                 value = ((JMenu) invoker).getClientProperty(Options.NO_ICONS_KEY);
644         }
645         return Boolean.TRUE.equals(value);
646     }
647     
648     
649     // Used as a placeholder if icons are disabled
650
private static class NullIcon implements Icon {
651         public int getIconWidth() { return 0; }
652         public int getIconHeight() { return 0; }
653         public void paintIcon(Component c, Graphics g, int x, int y) {
654             // The NullIcon doesn't paint anything.
655
}
656     }
657     
658     
659
660 }
Popular Tags