History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/plaf/basic/BasicMenuItemUI.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/plaf/basic/BasicMenuItemUI.java+972−0
@@ -0,0 +1,972 @@
1+/*
2+ * Copyright (c) 1997, 2008, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package javax.swing.plaf.basic;
27+
28+import java.awt.*;
29+import java.awt.event.*;
30+import java.beans.PropertyChangeEvent;
31+import java.beans.PropertyChangeListener;
32+
33+import javax.swing.*;
34+import javax.swing.event.*;
35+import javax.swing.plaf.*;
36+import javax.swing.text.View;
37+
38+import sun.swing.*;
39+
40+/**
41+ * BasicMenuItem implementation
42+ *
43+ * @author Georges Saab
44+ * @author David Karlton
45+ * @author Arnaud Weber
46+ * @author Fredrik Lagerblad
47+ */
48+public class BasicMenuItemUI extends MenuItemUI
49+{
50+ protected JMenuItem menuItem = null;
51+ protected Color selectionBackground;
52+ protected Color selectionForeground;
53+ protected Color disabledForeground;
54+ protected Color acceleratorForeground;
55+ protected Color acceleratorSelectionForeground;
56+
57+ /**
58+ * Accelerator delimiter string, such as {@code '+'} in {@code 'Ctrl+C'}.
59+ * @since 1.7
60+ */
61+ protected 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+ static void loadActionMap(LazyActionMap map) {
95+ // NOTE: BasicMenuUI also calls into this method.
96+ map.put(new Actions(Actions.CLICK));
97+ BasicLookAndFeel.installAudioActionMap(map);
98+ }
99+
100+ public static ComponentUI createUI(JComponent c) {
101+ return new BasicMenuItemUI();
102+ }
103+
104+ public void installUI(JComponent c) {
105+ menuItem = (JMenuItem) c;
106+
107+ installDefaults();
108+ installComponents(menuItem);
109+ installListeners();
110+ installKeyboardActions();
111+ }
112+
113+
114+ protected void installDefaults() {
115+ String prefix = getPropertyPrefix();
116+
117+ acceleratorFont = UIManager.getFont("MenuItem.acceleratorFont");
118+ // use default if missing so that BasicMenuItemUI can be used in other
119+ // LAFs like Nimbus
120+ if (acceleratorFont == null) {
121+ acceleratorFont = UIManager.getFont("MenuItem.font");
122+ }
123+
124+ Object opaque = UIManager.get(getPropertyPrefix() + ".opaque");
125+ if (opaque != null) {
126+ LookAndFeel.installProperty(menuItem, "opaque", opaque);
127+ }
128+ else {
129+ LookAndFeel.installProperty(menuItem, "opaque", Boolean.TRUE);
130+ }
131+ if(menuItem.getMargin() == null ||
132+ (menuItem.getMargin() instanceof UIResource)) {
133+ menuItem.setMargin(UIManager.getInsets(prefix + ".margin"));
134+ }
135+
136+ LookAndFeel.installProperty(menuItem, "iconTextGap", Integer.valueOf(4));
137+ defaultTextIconGap = menuItem.getIconTextGap();
138+
139+ LookAndFeel.installBorder(menuItem, prefix + ".border");
140+ oldBorderPainted = menuItem.isBorderPainted();
141+ LookAndFeel.installProperty(menuItem, "borderPainted",
142+ UIManager.getBoolean(prefix + ".borderPainted"));
143+ LookAndFeel.installColorsAndFont(menuItem,
144+ prefix + ".background",
145+ prefix + ".foreground",
146+ prefix + ".font");
147+
148+ // MenuItem specific defaults
149+ if (selectionBackground == null ||
150+ selectionBackground instanceof UIResource) {
151+ selectionBackground =
152+ UIManager.getColor(prefix + ".selectionBackground");
153+ }
154+ if (selectionForeground == null ||
155+ selectionForeground instanceof UIResource) {
156+ selectionForeground =
157+ UIManager.getColor(prefix + ".selectionForeground");
158+ }
159+ if (disabledForeground == null ||
160+ disabledForeground instanceof UIResource) {
161+ disabledForeground =
162+ UIManager.getColor(prefix + ".disabledForeground");
163+ }
164+ if (acceleratorForeground == null ||
165+ acceleratorForeground instanceof UIResource) {
166+ acceleratorForeground =
167+ UIManager.getColor(prefix + ".acceleratorForeground");
168+ }
169+ if (acceleratorSelectionForeground == null ||
170+ acceleratorSelectionForeground instanceof UIResource) {
171+ acceleratorSelectionForeground =
172+ UIManager.getColor(prefix + ".acceleratorSelectionForeground");
173+ }
174+ // Get accelerator delimiter
175+ acceleratorDelimiter =
176+ UIManager.getString("MenuItem.acceleratorDelimiter");
177+ if (acceleratorDelimiter == null) { acceleratorDelimiter = "+"; }
178+ // Icons
179+ if (arrowIcon == null ||
180+ arrowIcon instanceof UIResource) {
181+ arrowIcon = UIManager.getIcon(prefix + ".arrowIcon");
182+ }
183+ if (checkIcon == null ||
184+ checkIcon instanceof UIResource) {
185+ checkIcon = UIManager.getIcon(prefix + ".checkIcon");
186+ //In case of column layout, .checkIconFactory is defined for this UI,
187+ //the icon is compatible with it and useCheckAndArrow() is true,
188+ //then the icon is handled by the checkIcon.
189+ boolean isColumnLayout = MenuItemLayoutHelper.isColumnLayout(
190+ BasicGraphicsUtils.isLeftToRight(menuItem), menuItem);
191+ if (isColumnLayout) {
192+ MenuItemCheckIconFactory iconFactory =
193+ (MenuItemCheckIconFactory) UIManager.get(prefix
194+ + ".checkIconFactory");
195+ if (iconFactory != null
196+ && MenuItemLayoutHelper.useCheckAndArrow(menuItem)
197+ && iconFactory.isCompatible(checkIcon, prefix)) {
198+ checkIcon = iconFactory.getIcon(menuItem);
199+ }
200+ }
201+ }
202+ }
203+
204+ /**
205+ * @since 1.3
206+ */
207+ protected void installComponents(JMenuItem menuItem){
208+ BasicHTML.updateRenderer(menuItem, menuItem.getText());
209+ }
210+
211+ protected String getPropertyPrefix() {
212+ return "MenuItem";
213+ }
214+
215+ protected void installListeners() {
216+ if ((mouseInputListener = createMouseInputListener(menuItem)) != null) {
217+ menuItem.addMouseListener(mouseInputListener);
218+ menuItem.addMouseMotionListener(mouseInputListener);
219+ }
220+ if ((menuDragMouseListener = createMenuDragMouseListener(menuItem)) != null) {
221+ menuItem.addMenuDragMouseListener(menuDragMouseListener);
222+ }
223+ if ((menuKeyListener = createMenuKeyListener(menuItem)) != null) {
224+ menuItem.addMenuKeyListener(menuKeyListener);
225+ }
226+ if ((propertyChangeListener = createPropertyChangeListener(menuItem)) != null) {
227+ menuItem.addPropertyChangeListener(propertyChangeListener);
228+ }
229+ }
230+
231+ protected void installKeyboardActions() {
232+ installLazyActionMap();
233+ updateAcceleratorBinding();
234+ }
235+
236+ void installLazyActionMap() {
237+ LazyActionMap.installLazyActionMap(menuItem, BasicMenuItemUI.class,
238+ getPropertyPrefix() + ".actionMap");
239+ }
240+
241+ public void uninstallUI(JComponent c) {
242+ menuItem = (JMenuItem)c;
243+ uninstallDefaults();
244+ uninstallComponents(menuItem);
245+ uninstallListeners();
246+ uninstallKeyboardActions();
247+ MenuItemLayoutHelper.clearUsedParentClientProperties(menuItem);
248+ menuItem = null;
249+ }
250+
251+
252+ protected void uninstallDefaults() {
253+ LookAndFeel.uninstallBorder(menuItem);
254+ LookAndFeel.installProperty(menuItem, "borderPainted", oldBorderPainted);
255+ if (menuItem.getMargin() instanceof UIResource)
256+ menuItem.setMargin(null);
257+ if (arrowIcon instanceof UIResource)
258+ arrowIcon = null;
259+ if (checkIcon instanceof UIResource)
260+ checkIcon = null;
261+ }
262+
263+ /**
264+ * @since 1.3
265+ */
266+ protected void uninstallComponents(JMenuItem menuItem){
267+ BasicHTML.updateRenderer(menuItem, "");
268+ }
269+
270+ protected void uninstallListeners() {
271+ if (mouseInputListener != null) {
272+ menuItem.removeMouseListener(mouseInputListener);
273+ menuItem.removeMouseMotionListener(mouseInputListener);
274+ }
275+ if (menuDragMouseListener != null) {
276+ menuItem.removeMenuDragMouseListener(menuDragMouseListener);
277+ }
278+ if (menuKeyListener != null) {
279+ menuItem.removeMenuKeyListener(menuKeyListener);
280+ }
281+ if (propertyChangeListener != null) {
282+ menuItem.removePropertyChangeListener(propertyChangeListener);
283+ }
284+
285+ mouseInputListener = null;
286+ menuDragMouseListener = null;
287+ menuKeyListener = null;
288+ propertyChangeListener = null;
289+ handler = null;
290+ }
291+
292+ protected void uninstallKeyboardActions() {
293+ SwingUtilities.replaceUIActionMap(menuItem, null);
294+ SwingUtilities.replaceUIInputMap(menuItem, JComponent.
295+ WHEN_IN_FOCUSED_WINDOW, null);
296+ }
297+
298+ protected MouseInputListener createMouseInputListener(JComponent c) {
299+ return getHandler();
300+ }
301+
302+ protected MenuDragMouseListener createMenuDragMouseListener(JComponent c) {
303+ return getHandler();
304+ }
305+
306+ protected MenuKeyListener createMenuKeyListener(JComponent c) {
307+ return null;
308+ }
309+
310+ /**
311+ * Creates a <code>PropertyChangeListener</code> which will be added to
312+ * the menu item.
313+ * If this method returns null then it will not be added to the menu item.
314+ *
315+ * @return an instance of a <code>PropertyChangeListener</code> or null
316+ * @since 1.6
317+ */
318+ protected PropertyChangeListener
319+ createPropertyChangeListener(JComponent c) {
320+ return getHandler();
321+ }
322+
323+ Handler getHandler() {
324+ if (handler == null) {
325+ handler = new Handler();
326+ }
327+ return handler;
328+ }
329+
330+ InputMap createInputMap(int condition) {
331+ if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
332+ return new ComponentInputMapUIResource(menuItem);
333+ }
334+ return null;
335+ }
336+
337+ void updateAcceleratorBinding() {
338+ KeyStroke accelerator = menuItem.getAccelerator();
339+ InputMap windowInputMap = SwingUtilities.getUIInputMap(
340+ menuItem, JComponent.WHEN_IN_FOCUSED_WINDOW);
341+
342+ if (windowInputMap != null) {
343+ windowInputMap.clear();
344+ }
345+ if (accelerator != null) {
346+ if (windowInputMap == null) {
347+ windowInputMap = createInputMap(JComponent.
348+ WHEN_IN_FOCUSED_WINDOW);
349+ SwingUtilities.replaceUIInputMap(menuItem,
350+ JComponent.WHEN_IN_FOCUSED_WINDOW, windowInputMap);
351+ }
352+ windowInputMap.put(accelerator, "doClick");
353+ }
354+ }
355+
356+ public Dimension getMinimumSize(JComponent c) {
357+ Dimension d = null;
358+ View v = (View) c.getClientProperty(BasicHTML.propertyKey);
359+ if (v != null) {
360+ d = getPreferredSize(c);
361+ d.width -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS);
362+ }
363+ return d;
364+ }
365+
366+ public Dimension getPreferredSize(JComponent c) {
367+ return getPreferredMenuItemSize(c,
368+ checkIcon,
369+ arrowIcon,
370+ defaultTextIconGap);
371+ }
372+
373+ public Dimension getMaximumSize(JComponent c) {
374+ Dimension d = null;
375+ View v = (View) c.getClientProperty(BasicHTML.propertyKey);
376+ if (v != null) {
377+ d = getPreferredSize(c);
378+ d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS);
379+ }
380+ return d;
381+ }
382+
383+ protected Dimension getPreferredMenuItemSize(JComponent c,
384+ Icon checkIcon,
385+ Icon arrowIcon,
386+ int defaultTextIconGap) {
387+
388+ // The method also determines the preferred width of the
389+ // parent popup menu (through DefaultMenuLayout class).
390+ // The menu width equals to the maximal width
391+ // among child menu items.
392+
393+ // Menu item width will be a sum of the widest check icon, label,
394+ // arrow icon and accelerator text among neighbor menu items.
395+ // For the latest menu item we will know the maximal widths exactly.
396+ // It will be the widest menu item and it will determine
397+ // the width of the parent popup menu.
398+
399+ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
400+ // There is a conceptual problem: if user sets preferred size manually
401+ // for a menu item, this method won't be called for it
402+ // (see JComponent.getPreferredSize()),
403+ // maximal widths won't be calculated, other menu items won't be able
404+ // to take them into account and will be layouted in such a way,
405+ // as there is no the item with manual preferred size.
406+ // But after the first paint() method call, all maximal widths
407+ // will be correctly calculated and layout of some menu items
408+ // can be changed. For example, it can cause a shift of
409+ // the icon and text when user points a menu item by mouse.
410+
411+ JMenuItem mi = (JMenuItem) c;
412+ MenuItemLayoutHelper lh = new MenuItemLayoutHelper(mi, checkIcon,
413+ arrowIcon, MenuItemLayoutHelper.createMaxRect(), defaultTextIconGap,
414+ acceleratorDelimiter, BasicGraphicsUtils.isLeftToRight(mi),
415+ mi.getFont(), acceleratorFont,
416+ MenuItemLayoutHelper.useCheckAndArrow(menuItem),
417+ getPropertyPrefix());
418+
419+ Dimension result = new Dimension();
420+
421+ // Calculate the result width
422+ result.width = lh.getLeadingGap();
423+ MenuItemLayoutHelper.addMaxWidth(lh.getCheckSize(),
424+ lh.getAfterCheckIconGap(), result);
425+ // Take into account mimimal text offset.
426+ if ((!lh.isTopLevelMenu())
427+ && (lh.getMinTextOffset() > 0)
428+ && (result.width < lh.getMinTextOffset())) {
429+ result.width = lh.getMinTextOffset();
430+ }
431+ MenuItemLayoutHelper.addMaxWidth(lh.getLabelSize(), lh.getGap(), result);
432+ MenuItemLayoutHelper.addMaxWidth(lh.getAccSize(), lh.getGap(), result);
433+ MenuItemLayoutHelper.addMaxWidth(lh.getArrowSize(), lh.getGap(), result);
434+
435+ // Calculate the result height
436+ result.height = MenuItemLayoutHelper.max(lh.getCheckSize().getHeight(),
437+ lh.getLabelSize().getHeight(), lh.getAccSize().getHeight(),
438+ lh.getArrowSize().getHeight());
439+
440+ // Take into account menu item insets
441+ Insets insets = lh.getMenuItem().getInsets();
442+ if(insets != null) {
443+ result.width += insets.left + insets.right;
444+ result.height += insets.top + insets.bottom;
445+ }
446+
447+ // if the width is even, bump it up one. This is critical
448+ // for the focus dash line to draw properly
449+ if(result.width%2 == 0) {
450+ result.width++;
451+ }
452+
453+ // if the height is even, bump it up one. This is critical
454+ // for the text to center properly
455+ if(result.height%2 == 0
456+ && Boolean.TRUE !=
457+ UIManager.get(getPropertyPrefix() + ".evenHeight")) {
458+ result.height++;
459+ }
460+
461+ return result;
462+ }
463+
464+ /**
465+ * We draw the background in paintMenuItem()
466+ * so override update (which fills the background of opaque
467+ * components by default) to just call paint().
468+ *
469+ */
470+ public void update(Graphics g, JComponent c) {
471+ paint(g, c);
472+ }
473+
474+ public void paint(Graphics g, JComponent c) {
475+ paintMenuItem(g, c, checkIcon, arrowIcon,
476+ selectionBackground, selectionForeground,
477+ defaultTextIconGap);
478+ }
479+
480+ protected void paintMenuItem(Graphics g, JComponent c,
481+ Icon checkIcon, Icon arrowIcon,
482+ Color background, Color foreground,
483+ int defaultTextIconGap) {
484+ // Save original graphics font and color
485+ Font holdf = g.getFont();
486+ Color holdc = g.getColor();
487+
488+ JMenuItem mi = (JMenuItem) c;
489+ g.setFont(mi.getFont());
490+
491+ Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight());
492+ applyInsets(viewRect, mi.getInsets());
493+
494+ MenuItemLayoutHelper lh = new MenuItemLayoutHelper(mi, checkIcon,
495+ arrowIcon, viewRect, defaultTextIconGap, acceleratorDelimiter,
496+ BasicGraphicsUtils.isLeftToRight(mi), mi.getFont(),
497+ acceleratorFont, MenuItemLayoutHelper.useCheckAndArrow(menuItem),
498+ getPropertyPrefix());
499+ MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem();
500+
501+ paintBackground(g, mi, background);
502+ paintCheckIcon(g, lh, lr, holdc, foreground);
503+ paintIcon(g, lh, lr, holdc);
504+ paintText(g, lh, lr);
505+ paintAccText(g, lh, lr);
506+ paintArrowIcon(g, lh, lr, foreground);
507+
508+ // Restore original graphics font and color
509+ g.setColor(holdc);
510+ g.setFont(holdf);
511+ }
512+
513+ private void paintIcon(Graphics g, MenuItemLayoutHelper lh,
514+ MenuItemLayoutHelper.LayoutResult lr, Color holdc) {
515+ if (lh.getIcon() != null) {
516+ Icon icon;
517+ ButtonModel model = lh.getMenuItem().getModel();
518+ if (!model.isEnabled()) {
519+ icon = lh.getMenuItem().getDisabledIcon();
520+ } else if (model.isPressed() && model.isArmed()) {
521+ icon = lh.getMenuItem().getPressedIcon();
522+ if (icon == null) {
523+ // Use default icon
524+ icon = lh.getMenuItem().getIcon();
525+ }
526+ } else {
527+ icon = lh.getMenuItem().getIcon();
528+ }
529+
530+ if (icon != null) {
531+ icon.paintIcon(lh.getMenuItem(), g, lr.getIconRect().x,
532+ lr.getIconRect().y);
533+ g.setColor(holdc);
534+ }
535+ }
536+ }
537+
538+ private void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh,
539+ MenuItemLayoutHelper.LayoutResult lr,
540+ Color holdc, Color foreground) {
541+ if (lh.getCheckIcon() != null) {
542+ ButtonModel model = lh.getMenuItem().getModel();
543+ if (model.isArmed() || (lh.getMenuItem() instanceof JMenu
544+ && model.isSelected())) {
545+ g.setColor(foreground);
546+ } else {
547+ g.setColor(holdc);
548+ }
549+ if (lh.useCheckAndArrow()) {
550+ lh.getCheckIcon().paintIcon(lh.getMenuItem(), g,
551+ lr.getCheckRect().x, lr.getCheckRect().y);
552+ }
553+ g.setColor(holdc);
554+ }
555+ }
556+
557+ private void paintAccText(Graphics g, MenuItemLayoutHelper lh,
558+ MenuItemLayoutHelper.LayoutResult lr) {
559+ if (!lh.getAccText().equals("")) {
560+ ButtonModel model = lh.getMenuItem().getModel();
561+ g.setFont(lh.getAccFontMetrics().getFont());
562+ if (!model.isEnabled()) {
563+ // *** paint the accText disabled
564+ if (disabledForeground != null) {
565+ g.setColor(disabledForeground);
566+ SwingUtilities2.drawString(lh.getMenuItem(), g,
567+ lh.getAccText(), lr.getAccRect().x,
568+ lr.getAccRect().y + lh.getAccFontMetrics().getAscent());
569+ } else {
570+ g.setColor(lh.getMenuItem().getBackground().brighter());
571+ SwingUtilities2.drawString(lh.getMenuItem(), g,
572+ lh.getAccText(), lr.getAccRect().x,
573+ lr.getAccRect().y + lh.getAccFontMetrics().getAscent());
574+ g.setColor(lh.getMenuItem().getBackground().darker());
575+ SwingUtilities2.drawString(lh.getMenuItem(), g,
576+ lh.getAccText(), lr.getAccRect().x - 1,
577+ lr.getAccRect().y + lh.getFontMetrics().getAscent() - 1);
578+ }
579+ } else {
580+ // *** paint the accText normally
581+ if (model.isArmed()
582+ || (lh.getMenuItem() instanceof JMenu
583+ && model.isSelected())) {
584+ g.setColor(acceleratorSelectionForeground);
585+ } else {
586+ g.setColor(acceleratorForeground);
587+ }
588+ SwingUtilities2.drawString(lh.getMenuItem(), g, lh.getAccText(),
589+ lr.getAccRect().x, lr.getAccRect().y +
590+ lh.getAccFontMetrics().getAscent());
591+ }
592+ }
593+ }
594+
595+ private void paintText(Graphics g, MenuItemLayoutHelper lh,
596+ MenuItemLayoutHelper.LayoutResult lr) {
597+ if (!lh.getText().equals("")) {
598+ if (lh.getHtmlView() != null) {
599+ // Text is HTML
600+ lh.getHtmlView().paint(g, lr.getTextRect());
601+ } else {
602+ // Text isn't HTML
603+ paintText(g, lh.getMenuItem(), lr.getTextRect(), lh.getText());
604+ }
605+ }
606+ }
607+
608+ private void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh,
609+ MenuItemLayoutHelper.LayoutResult lr,
610+ Color foreground) {
611+ if (lh.getArrowIcon() != null) {
612+ ButtonModel model = lh.getMenuItem().getModel();
613+ if (model.isArmed() || (lh.getMenuItem() instanceof JMenu
614+ && model.isSelected())) {
615+ g.setColor(foreground);
616+ }
617+ if (lh.useCheckAndArrow()) {
618+ lh.getArrowIcon().paintIcon(lh.getMenuItem(), g,
619+ lr.getArrowRect().x, lr.getArrowRect().y);
620+ }
621+ }
622+ }
623+
624+ private void applyInsets(Rectangle rect, Insets insets) {
625+ if(insets != null) {
626+ rect.x += insets.left;
627+ rect.y += insets.top;
628+ rect.width -= (insets.right + rect.x);
629+ rect.height -= (insets.bottom + rect.y);
630+ }
631+ }
632+
633+ /**
634+ * Draws the background of the menu item.
635+ *
636+ * @param g the paint graphics
637+ * @param menuItem menu item to be painted
638+ * @param bgColor selection background color
639+ * @since 1.4
640+ */
641+ protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) {
642+ ButtonModel model = menuItem.getModel();
643+ Color oldColor = g.getColor();
644+ int menuWidth = menuItem.getWidth();
645+ int menuHeight = menuItem.getHeight();
646+
647+ if(menuItem.isOpaque()) {
648+ if (model.isArmed()|| (menuItem instanceof JMenu && model.isSelected())) {
649+ g.setColor(bgColor);
650+ g.fillRect(0,0, menuWidth, menuHeight);
651+ } else {
652+ g.setColor(menuItem.getBackground());
653+ g.fillRect(0,0, menuWidth, menuHeight);
654+ }
655+ g.setColor(oldColor);
656+ }
657+ else if (model.isArmed() || (menuItem instanceof JMenu &&
658+ model.isSelected())) {
659+ g.setColor(bgColor);
660+ g.fillRect(0,0, menuWidth, menuHeight);
661+ g.setColor(oldColor);
662+ }
663+ }
664+
665+ /**
666+ * Renders the text of the current menu item.
667+ * <p>
668+ * @param g graphics context
669+ * @param menuItem menu item to render
670+ * @param textRect bounding rectangle for rendering the text
671+ * @param text string to render
672+ * @since 1.4
673+ */
674+ protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) {
675+ ButtonModel model = menuItem.getModel();
676+ FontMetrics fm = SwingUtilities2.getFontMetrics(menuItem, g);
677+ int mnemIndex = menuItem.getDisplayedMnemonicIndex();
678+
679+ if(!model.isEnabled()) {
680+ // *** paint the text disabled
681+ if ( UIManager.get("MenuItem.disabledForeground") instanceof Color ) {
682+ g.setColor( UIManager.getColor("MenuItem.disabledForeground") );
683+ SwingUtilities2.drawStringUnderlineCharAt(menuItem, g,text,
684+ mnemIndex, textRect.x, textRect.y + fm.getAscent());
685+ } else {
686+ g.setColor(menuItem.getBackground().brighter());
687+ SwingUtilities2.drawStringUnderlineCharAt(menuItem, g, text,
688+ mnemIndex, textRect.x, textRect.y + fm.getAscent());
689+ g.setColor(menuItem.getBackground().darker());
690+ SwingUtilities2.drawStringUnderlineCharAt(menuItem, g,text,
691+ mnemIndex, textRect.x - 1, textRect.y +
692+ fm.getAscent() - 1);
693+ }
694+ } else {
695+ // *** paint the text normally
696+ if (model.isArmed()|| (menuItem instanceof JMenu && model.isSelected())) {
697+ g.setColor(selectionForeground); // Uses protected field.
698+ }
699+ SwingUtilities2.drawStringUnderlineCharAt(menuItem, g,text,
700+ mnemIndex, textRect.x, textRect.y + fm.getAscent());
701+ }
702+ }
703+
704+ public MenuElement[] getPath() {
705+ MenuSelectionManager m = MenuSelectionManager.defaultManager();
706+ MenuElement oldPath[] = m.getSelectedPath();
707+ MenuElement newPath[];
708+ int i = oldPath.length;
709+ if (i == 0)
710+ return new MenuElement[0];
711+ Component parent = menuItem.getParent();
712+ if (oldPath[i-1].getComponent() == parent) {
713+ // The parent popup menu is the last so far
714+ newPath = new MenuElement[i+1];
715+ System.arraycopy(oldPath, 0, newPath, 0, i);
716+ newPath[i] = menuItem;
717+ } else {
718+ // A sibling menuitem is the current selection
719+ //
720+ // This probably needs to handle 'exit submenu into
721+ // a menu item. Search backwards along the current
722+ // selection until you find the parent popup menu,
723+ // then copy up to that and add yourself...
724+ int j;
725+ for (j = oldPath.length-1; j >= 0; j--) {
726+ if (oldPath[j].getComponent() == parent)
727+ break;
728+ }
729+ newPath = new MenuElement[j+2];
730+ System.arraycopy(oldPath, 0, newPath, 0, j+1);
731+ newPath[j+1] = menuItem;
732+ /*
733+ System.out.println("Sibling condition -- ");
734+ System.out.println("Old array : ");
735+ printMenuElementArray(oldPath, false);
736+ System.out.println("New array : ");
737+ printMenuElementArray(newPath, false);
738+ */
739+ }
740+ return newPath;
741+ }
742+
743+ void printMenuElementArray(MenuElement path[], boolean dumpStack) {
744+ System.out.println("Path is(");
745+ int i, j;
746+ for(i=0,j=path.length; i<j ;i++){
747+ for (int k=0; k<=i; k++)
748+ System.out.print(" ");
749+ MenuElement me = path[i];
750+ if(me instanceof JMenuItem)
751+ System.out.println(((JMenuItem)me).getText() + ", ");
752+ else if (me == null)
753+ System.out.println("NULL , ");
754+ else
755+ System.out.println("" + me + ", ");
756+ }
757+ System.out.println(")");
758+
759+ if (dumpStack == true)
760+ Thread.dumpStack();
761+ }
762+ protected class MouseInputHandler implements MouseInputListener {
763+ // NOTE: This class exists only for backward compatability. All
764+ // its functionality has been moved into Handler. If you need to add
765+ // new functionality add it to the Handler, but make sure this
766+ // class calls into the Handler.
767+
768+ public void mouseClicked(MouseEvent e) {
769+ getHandler().mouseClicked(e);
770+ }
771+ public void mousePressed(MouseEvent e) {
772+ getHandler().mousePressed(e);
773+ }
774+ public void mouseReleased(MouseEvent e) {
775+ getHandler().mouseReleased(e);
776+ }
777+ public void mouseEntered(MouseEvent e) {
778+ getHandler().mouseEntered(e);
779+ }
780+ public void mouseExited(MouseEvent e) {
781+ getHandler().mouseExited(e);
782+ }
783+ public void mouseDragged(MouseEvent e) {
784+ getHandler().mouseDragged(e);
785+ }
786+ public void mouseMoved(MouseEvent e) {
787+ getHandler().mouseMoved(e);
788+ }
789+ }
790+
791+
792+ private static class Actions extends UIAction {
793+ private static final String CLICK = "doClick";
794+
795+ Actions(String key) {
796+ super(key);
797+ }
798+
799+ public void actionPerformed(ActionEvent e) {
800+ JMenuItem mi = (JMenuItem)e.getSource();
801+ MenuSelectionManager.defaultManager().clearSelectedPath();
802+ mi.doClick();
803+ }
804+ }
805+
806+ /**
807+ * Call this method when a menu item is to be activated.
808+ * This method handles some of the details of menu item activation
809+ * such as clearing the selected path and messaging the
810+ * JMenuItem's doClick() method.
811+ *
812+ * @param msm A MenuSelectionManager. The visual feedback and
813+ * internal bookkeeping tasks are delegated to
814+ * this MenuSelectionManager. If <code>null</code> is
815+ * passed as this argument, the
816+ * <code>MenuSelectionManager.defaultManager</code> is
817+ * used.
818+ * @see MenuSelectionManager
819+ * @see JMenuItem#doClick(int)
820+ * @since 1.4
821+ */
822+ protected void doClick(MenuSelectionManager msm) {
823+ // Auditory cue
824+ if (! isInternalFrameSystemMenu()) {
825+ BasicLookAndFeel.playSound(menuItem, getPropertyPrefix() +
826+ ".commandSound");
827+ }
828+ // Visual feedback
829+ if (msm == null) {
830+ msm = MenuSelectionManager.defaultManager();
831+ }
832+ msm.clearSelectedPath();
833+ menuItem.doClick(0);
834+ }
835+
836+ /**
837+ * This is to see if the menu item in question is part of the
838+ * system menu on an internal frame.
839+ * The Strings that are being checked can be found in
840+ * MetalInternalFrameTitlePaneUI.java,
841+ * WindowsInternalFrameTitlePaneUI.java, and
842+ * MotifInternalFrameTitlePaneUI.java.
843+ *
844+ * @since 1.4
845+ */
846+ private boolean isInternalFrameSystemMenu() {
847+ String actionCommand = menuItem.getActionCommand();
848+ if ((actionCommand == "Close") ||
849+ (actionCommand == "Minimize") ||
850+ (actionCommand == "Restore") ||
851+ (actionCommand == "Maximize")) {
852+ return true;
853+ } else {
854+ return false;
855+ }
856+ }
857+
858+
859+ // BasicMenuUI subclasses this.
860+ class Handler implements MenuDragMouseListener,
861+ MouseInputListener, PropertyChangeListener {
862+ //
863+ // MouseInputListener
864+ //
865+ public void mouseClicked(MouseEvent e) {}
866+ public void mousePressed(MouseEvent e) {
867+ }
868+ public void mouseReleased(MouseEvent e) {
869+ if (!menuItem.isEnabled()) {
870+ return;
871+ }
872+ MenuSelectionManager manager =
873+ MenuSelectionManager.defaultManager();
874+ Point p = e.getPoint();
875+ if(p.x >= 0 && p.x < menuItem.getWidth() &&
876+ p.y >= 0 && p.y < menuItem.getHeight()) {
877+ doClick(manager);
878+ } else {
879+ manager.processMouseEvent(e);
880+ }
881+ }
882+ public void mouseEntered(MouseEvent e) {
883+ MenuSelectionManager manager = MenuSelectionManager.defaultManager();
884+ int modifiers = e.getModifiers();
885+ // 4188027: drag enter/exit added in JDK 1.1.7A, JDK1.2
886+ if ((modifiers & (InputEvent.BUTTON1_MASK |
887+ InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK)) !=0 ) {
888+ MenuSelectionManager.defaultManager().processMouseEvent(e);
889+ } else {
890+ manager.setSelectedPath(getPath());
891+ }
892+ }
893+ public void mouseExited(MouseEvent e) {
894+ MenuSelectionManager manager = MenuSelectionManager.defaultManager();
895+
896+ int modifiers = e.getModifiers();
897+ // 4188027: drag enter/exit added in JDK 1.1.7A, JDK1.2
898+ if ((modifiers & (InputEvent.BUTTON1_MASK |
899+ InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK)) !=0 ) {
900+ MenuSelectionManager.defaultManager().processMouseEvent(e);
901+ } else {
902+
903+ MenuElement path[] = manager.getSelectedPath();
904+ if (path.length > 1 && path[path.length-1] == menuItem) {
905+ MenuElement newPath[] = new MenuElement[path.length-1];
906+ int i,c;
907+ for(i=0,c=path.length-1;i<c;i++)
908+ newPath[i] = path[i];
909+ manager.setSelectedPath(newPath);
910+ }
911+ }
912+ }
913+
914+ public void mouseDragged(MouseEvent e) {
915+ MenuSelectionManager.defaultManager().processMouseEvent(e);
916+ }
917+ public void mouseMoved(MouseEvent e) {
918+ }
919+
920+ //
921+ // MenuDragListener
922+ //
923+ public void menuDragMouseEntered(MenuDragMouseEvent e) {
924+ MenuSelectionManager manager = e.getMenuSelectionManager();
925+ MenuElement path[] = e.getPath();
926+ manager.setSelectedPath(path);
927+ }
928+ public void menuDragMouseDragged(MenuDragMouseEvent e) {
929+ MenuSelectionManager manager = e.getMenuSelectionManager();
930+ MenuElement path[] = e.getPath();
931+ manager.setSelectedPath(path);
932+ }
933+ public void menuDragMouseExited(MenuDragMouseEvent e) {}
934+ public void menuDragMouseReleased(MenuDragMouseEvent e) {
935+ if (!menuItem.isEnabled()) {
936+ return;
937+ }
938+ MenuSelectionManager manager = e.getMenuSelectionManager();
939+ MenuElement path[] = e.getPath();
940+ Point p = e.getPoint();
941+ if (p.x >= 0 && p.x < menuItem.getWidth() &&
942+ p.y >= 0 && p.y < menuItem.getHeight()) {
943+ doClick(manager);
944+ } else {
945+ manager.clearSelectedPath();
946+ }
947+ }
948+
949+
950+ //
951+ // PropertyChangeListener
952+ //
953+ public void propertyChange(PropertyChangeEvent e) {
954+ String name = e.getPropertyName();
955+
956+ if (name == "labelFor" || name == "displayedMnemonic" ||
957+ name == "accelerator") {
958+ updateAcceleratorBinding();
959+ } else if (name == "text" || "font" == name ||
960+ "foreground" == name) {
961+ // remove the old html view client property if one
962+ // existed, and install a new one if the text installed
963+ // into the JLabel is html source.
964+ JMenuItem lbl = ((JMenuItem) e.getSource());
965+ String text = lbl.getText();
966+ BasicHTML.updateRenderer(lbl, text);
967+ } else if (name == "iconTextGap") {
968+ defaultTextIconGap = ((Number)e.getNewValue()).intValue();
969+ }
970+ }
971+ }
972+}