J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 1997-2007 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 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 | * <p> |
| 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 | } |