1 /* 2 * Copyright (c) 1997, 2007, 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 com.sun.java.swing.plaf.windows; 27 28 import java.awt.*; 29 import java.awt.event.MouseEvent; 30 31 import javax.swing.plaf.ComponentUI; 32 import javax.swing.plaf.basic.BasicMenuUI; 33 import javax.swing.event.MouseInputListener; 34 import javax.swing.*; 35 36 import com.sun.java.swing.plaf.windows.TMSchema.Part; 37 import com.sun.java.swing.plaf.windows.TMSchema.State; 38 39 /** 40 * Windows rendition of the component. 41 * <p> 42 * <strong>Warning:</strong> 43 * Serialized objects of this class will not be compatible with 44 * future Swing releases. The current serialization support is appropriate 45 * for short term storage or RMI between applications running the same 46 * version of Swing. A future release of Swing will provide support for 47 * long term persistence. 48 */ 49 public class WindowsMenuUI extends BasicMenuUI { 50 protected Integer menuBarHeight; 51 protected boolean hotTrackingOn; 52 53 final WindowsMenuItemUIAccessor accessor = 54 new WindowsMenuItemUIAccessor() { 55 56 public JMenuItem getMenuItem() { 57 return menuItem; 58 } 59 60 public State getState(JMenuItem menu) { 61 State state = menu.isEnabled() ? State.NORMAL 62 : State.DISABLED; 63 ButtonModel model = menu.getModel(); 64 if (model.isArmed() || model.isSelected()) { 65 state = (menu.isEnabled()) ? State.PUSHED 66 : State.DISABLEDPUSHED; 67 } else if (model.isRollover() 68 && ((JMenu) menu).isTopLevelMenu()) { 69 /* 70 * Only paint rollover if no other menu on menubar is 71 * selected 72 */ 73 State stateTmp = state; 74 state = (menu.isEnabled()) ? State.HOT 75 : State.DISABLEDHOT; 76 for (MenuElement menuElement : 77 ((JMenuBar) menu.getParent()).getSubElements()) { 78 if (((JMenuItem) menuElement).isSelected()) { 79 state = stateTmp; 80 break; 81 } 82 } 83 } 84 85 //non top level menus have HOT state instead of PUSHED 86 if (!((JMenu) menu).isTopLevelMenu()) { 87 if (state == State.PUSHED) { 88 state = State.HOT; 89 } else if (state == State.DISABLEDPUSHED) { 90 state = State.DISABLEDHOT; 91 } 92 } 93 94 /* 95 * on Vista top level menu for non active frame looks disabled 96 */ 97 if (((JMenu) menu).isTopLevelMenu() && WindowsMenuItemUI.isVistaPainting()) { 98 if (! WindowsMenuBarUI.isActive(menu)) { 99 state = State.DISABLED; 100 } 101 } 102 return state; 103 } 104 105 public Part getPart(JMenuItem menuItem) { 106 return ((JMenu) menuItem).isTopLevelMenu() ? Part.MP_BARITEM 107 : Part.MP_POPUPITEM; 108 } 109 }; 110 public static ComponentUI createUI(JComponent x) { 111 return new WindowsMenuUI(); 112 } 113 114 protected void installDefaults() { 115 super.installDefaults(); 116 if (!WindowsLookAndFeel.isClassicWindows()) { 117 menuItem.setRolloverEnabled(true); 118 } 119 120 menuBarHeight = (Integer)UIManager.getInt("MenuBar.height"); 121 122 Object obj = UIManager.get("MenuBar.rolloverEnabled"); 123 hotTrackingOn = (obj instanceof Boolean) ? (Boolean)obj : true; 124 } 125 126 /** 127 * Draws the background of the menu. 128 * @since 1.4 129 */ 130 protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) { 131 if (WindowsMenuItemUI.isVistaPainting()) { 132 WindowsMenuItemUI.paintBackground(accessor, g, menuItem, bgColor); 133 return; 134 } 135 136 JMenu menu = (JMenu)menuItem; 137 ButtonModel model = menu.getModel(); 138 139 // Use superclass method for the old Windows LAF, 140 // for submenus, and for XP toplevel if selected or pressed 141 if (WindowsLookAndFeel.isClassicWindows() || 142 !menu.isTopLevelMenu() || 143 (XPStyle.getXP() != null && (model.isArmed() || model.isSelected()))) { 144 145 super.paintBackground(g, menu, bgColor); 146 return; 147 } 148 149 Color oldColor = g.getColor(); 150 int menuWidth = menu.getWidth(); 151 int menuHeight = menu.getHeight(); 152 153 UIDefaults table = UIManager.getLookAndFeelDefaults(); 154 Color highlight = table.getColor("controlLtHighlight"); 155 Color shadow = table.getColor("controlShadow"); 156 157 g.setColor(menu.getBackground()); 158 g.fillRect(0,0, menuWidth, menuHeight); 159 160 if (menu.isOpaque()) { 161 if (model.isArmed() || model.isSelected()) { 162 // Draw a lowered bevel border 163 g.setColor(shadow); 164 g.drawLine(0,0, menuWidth - 1,0); 165 g.drawLine(0,0, 0,menuHeight - 2); 166 167 g.setColor(highlight); 168 g.drawLine(menuWidth - 1,0, menuWidth - 1,menuHeight - 2); 169 g.drawLine(0,menuHeight - 2, menuWidth - 1,menuHeight - 2); 170 } else if (model.isRollover() && model.isEnabled()) { 171 // Only paint rollover if no other menu on menubar is selected 172 boolean otherMenuSelected = false; 173 MenuElement[] menus = ((JMenuBar)menu.getParent()).getSubElements(); 174 for (int i = 0; i < menus.length; i++) { 175 if (((JMenuItem)menus[i]).isSelected()) { 176 otherMenuSelected = true; 177 break; 178 } 179 } 180 if (!otherMenuSelected) { 181 if (XPStyle.getXP() != null) { 182 g.setColor(selectionBackground); // Uses protected field. 183 g.fillRect(0, 0, menuWidth, menuHeight); 184 } else { 185 // Draw a raised bevel border 186 g.setColor(highlight); 187 g.drawLine(0,0, menuWidth - 1,0); 188 g.drawLine(0,0, 0,menuHeight - 2); 189 190 g.setColor(shadow); 191 g.drawLine(menuWidth - 1,0, menuWidth - 1,menuHeight - 2); 192 g.drawLine(0,menuHeight - 2, menuWidth - 1,menuHeight - 2); 193 } 194 } 195 } 196 } 197 g.setColor(oldColor); 198 } 199 200 /** 201 * Method which renders the text of the current menu item. 202 * 203 * @param g Graphics context 204 * @param menuItem Current menu item to render 205 * @param textRect Bounding rectangle to render the text. 206 * @param text String to render 207 * @since 1.4 208 */ 209 protected void paintText(Graphics g, JMenuItem menuItem, 210 Rectangle textRect, String text) { 211 if (WindowsMenuItemUI.isVistaPainting()) { 212 WindowsMenuItemUI.paintText(accessor, g, menuItem, textRect, text); 213 return; 214 } 215 JMenu menu = (JMenu)menuItem; 216 ButtonModel model = menuItem.getModel(); 217 Color oldColor = g.getColor(); 218 219 // Only paint rollover if no other menu on menubar is selected 220 boolean paintRollover = model.isRollover(); 221 if (paintRollover && menu.isTopLevelMenu()) { 222 MenuElement[] menus = ((JMenuBar)menu.getParent()).getSubElements(); 223 for (int i = 0; i < menus.length; i++) { 224 if (((JMenuItem)menus[i]).isSelected()) { 225 paintRollover = false; 226 break; 227 } 228 } 229 } 230 231 if ((model.isSelected() && (WindowsLookAndFeel.isClassicWindows() || 232 !menu.isTopLevelMenu())) || 233 (XPStyle.getXP() != null && (paintRollover || 234 model.isArmed() || 235 model.isSelected()))) { 236 g.setColor(selectionForeground); // Uses protected field. 237 } 238 239 WindowsGraphicsUtils.paintText(g, menuItem, textRect, text, 0); 240 241 g.setColor(oldColor); 242 } 243 244 protected MouseInputListener createMouseInputListener(JComponent c) { 245 return new WindowsMouseInputHandler(); 246 } 247 248 /** 249 * This class implements a mouse handler that sets the rollover flag to 250 * true when the mouse enters the menu and false when it exits. 251 * @since 1.4 252 */ 253 protected class WindowsMouseInputHandler extends BasicMenuUI.MouseInputHandler { 254 public void mouseEntered(MouseEvent evt) { 255 super.mouseEntered(evt); 256 257 JMenu menu = (JMenu)evt.getSource(); 258 if (hotTrackingOn && menu.isTopLevelMenu() && menu.isRolloverEnabled()) { 259 menu.getModel().setRollover(true); 260 menuItem.repaint(); 261 } 262 } 263 264 public void mouseExited(MouseEvent evt) { 265 super.mouseExited(evt); 266 267 JMenu menu = (JMenu)evt.getSource(); 268 ButtonModel model = menu.getModel(); 269 if (menu.isRolloverEnabled()) { 270 model.setRollover(false); 271 menuItem.repaint(); 272 } 273 } 274 } 275 276 protected Dimension getPreferredMenuItemSize(JComponent c, 277 Icon checkIcon, 278 Icon arrowIcon, 279 int defaultTextIconGap) { 280 281 Dimension d = super.getPreferredMenuItemSize(c, checkIcon, arrowIcon, 282 defaultTextIconGap); 283 284 // Note: When toolbar containers (rebars) are implemented, only do 285 // this if the JMenuBar is not in a rebar (i.e. ignore the desktop 286 // property win.menu.height if in a rebar.) 287 if (c instanceof JMenu && ((JMenu)c).isTopLevelMenu() && 288 menuBarHeight != null && d.height < menuBarHeight) { 289 290 d.height = menuBarHeight; 291 } 292 293 return d; 294 } 295 }