1 /* 2 * Copyright (c) 2002, 2013, 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 package javax.swing.plaf.synth; 26 27 import java.awt.*; 28 import java.beans.*; 29 import javax.swing.*; 30 import javax.swing.plaf.*; 31 import javax.swing.plaf.basic.*; 32 import sun.swing.MenuItemLayoutHelper; 33 34 /** 35 * Provides the Synth L&F UI delegate for 36 * {@link javax.swing.JMenu}. 37 * 38 * @author Georges Saab 39 * @author David Karlton 40 * @author Arnaud Weber 41 * @since 1.7 42 */ 43 public class SynthMenuUI extends BasicMenuUI 44 implements PropertyChangeListener, SynthUI { 45 private SynthStyle style; 46 private SynthStyle accStyle; 47 48 /** 49 * Creates a new UI object for the given component. 50 * 51 * @param x component to create UI object for 52 * @return the UI object 53 */ createUI(JComponent x)54 public static ComponentUI createUI(JComponent x) { 55 return new SynthMenuUI(); 56 } 57 58 /** 59 * {@inheritDoc} 60 */ 61 @Override installDefaults()62 protected void installDefaults() { 63 updateStyle(menuItem); 64 } 65 66 /** 67 * {@inheritDoc} 68 */ 69 @Override installListeners()70 protected void installListeners() { 71 super.installListeners(); 72 menuItem.addPropertyChangeListener(this); 73 } 74 updateStyle(JMenuItem mi)75 private void updateStyle(JMenuItem mi) { 76 SynthStyle oldStyle = style; 77 SynthContext context = getContext(mi, ENABLED); 78 79 style = SynthLookAndFeel.updateStyle(context, this); 80 if (oldStyle != style) { 81 String prefix = getPropertyPrefix(); 82 defaultTextIconGap = style.getInt( 83 context, prefix + ".textIconGap", 4); 84 if (menuItem.getMargin() == null || 85 (menuItem.getMargin() instanceof UIResource)) { 86 Insets insets = (Insets)style.get(context, prefix + ".margin"); 87 88 if (insets == null) { 89 // Some places assume margins are non-null. 90 insets = SynthLookAndFeel.EMPTY_UIRESOURCE_INSETS; 91 } 92 menuItem.setMargin(insets); 93 } 94 acceleratorDelimiter = style.getString(context, prefix + 95 ".acceleratorDelimiter", "+"); 96 97 if (MenuItemLayoutHelper.useCheckAndArrow(menuItem)) { 98 checkIcon = style.getIcon(context, prefix + ".checkIcon"); 99 arrowIcon = style.getIcon(context, prefix + ".arrowIcon"); 100 } else { 101 // Not needed in this case 102 checkIcon = null; 103 arrowIcon = null; 104 } 105 106 ((JMenu)menuItem).setDelay(style.getInt(context, prefix + 107 ".delay", 200)); 108 if (oldStyle != null) { 109 uninstallKeyboardActions(); 110 installKeyboardActions(); 111 } 112 } 113 114 SynthContext accContext = getContext(mi, Region.MENU_ITEM_ACCELERATOR, 115 ENABLED); 116 117 accStyle = SynthLookAndFeel.updateStyle(accContext, this); 118 } 119 120 /** 121 * {@inheritDoc} 122 */ 123 @Override uninstallUI(JComponent c)124 public void uninstallUI(JComponent c) { 125 super.uninstallUI(c); 126 // Remove values from the parent's Client Properties. 127 JComponent p = MenuItemLayoutHelper.getMenuItemParent((JMenuItem) c); 128 if (p != null) { 129 p.putClientProperty( 130 SynthMenuItemLayoutHelper.MAX_ACC_OR_ARROW_WIDTH, null); 131 } 132 } 133 134 /** 135 * {@inheritDoc} 136 */ 137 @Override uninstallDefaults()138 protected void uninstallDefaults() { 139 SynthContext context = getContext(menuItem, ENABLED); 140 style.uninstallDefaults(context); 141 style = null; 142 143 SynthContext accContext = getContext(menuItem, 144 Region.MENU_ITEM_ACCELERATOR, ENABLED); 145 accStyle.uninstallDefaults(accContext); 146 accStyle = null; 147 148 super.uninstallDefaults(); 149 } 150 151 /** 152 * {@inheritDoc} 153 */ 154 @Override uninstallListeners()155 protected void uninstallListeners() { 156 super.uninstallListeners(); 157 menuItem.removePropertyChangeListener(this); 158 } 159 160 /** 161 * {@inheritDoc} 162 */ 163 @Override getContext(JComponent c)164 public SynthContext getContext(JComponent c) { 165 return getContext(c, getComponentState(c)); 166 } 167 getContext(JComponent c, int state)168 SynthContext getContext(JComponent c, int state) { 169 return SynthContext.getContext(c, style, state); 170 } 171 getContext(JComponent c, Region region)172 SynthContext getContext(JComponent c, Region region) { 173 return getContext(c, region, getComponentState(c, region)); 174 } 175 getContext(JComponent c, Region region, int state)176 private SynthContext getContext(JComponent c, Region region, int state) { 177 return SynthContext.getContext(c, region, accStyle, state); 178 } 179 getComponentState(JComponent c)180 private int getComponentState(JComponent c) { 181 int state; 182 183 if (!c.isEnabled()) { 184 return DISABLED; 185 } 186 if (menuItem.isArmed()) { 187 state = MOUSE_OVER; 188 } 189 else { 190 state = SynthLookAndFeel.getComponentState(c); 191 } 192 if (menuItem.isSelected()) { 193 state |= SELECTED; 194 } 195 return state; 196 } 197 getComponentState(JComponent c, Region region)198 private int getComponentState(JComponent c, Region region) { 199 return getComponentState(c); 200 } 201 202 /** 203 * {@inheritDoc} 204 */ 205 @Override getPreferredMenuItemSize(JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap)206 protected Dimension getPreferredMenuItemSize(JComponent c, 207 Icon checkIcon, 208 Icon arrowIcon, 209 int defaultTextIconGap) { 210 SynthContext context = getContext(c); 211 SynthContext accContext = getContext(c, Region.MENU_ITEM_ACCELERATOR); 212 Dimension value = SynthGraphicsUtils.getPreferredMenuItemSize( 213 context, accContext, c, checkIcon, arrowIcon, 214 defaultTextIconGap, acceleratorDelimiter, 215 MenuItemLayoutHelper.useCheckAndArrow(menuItem), 216 getPropertyPrefix()); 217 return value; 218 } 219 220 /** 221 * Notifies this UI delegate to repaint the specified component. 222 * This method paints the component background, then calls 223 * the {@link #paint(SynthContext,Graphics)} method. 224 * 225 * <p>In general, this method does not need to be overridden by subclasses. 226 * All Look and Feel rendering code should reside in the {@code paint} method. 227 * 228 * @param g the {@code Graphics} object used for painting 229 * @param c the component being painted 230 * @see #paint(SynthContext,Graphics) 231 */ 232 @Override update(Graphics g, JComponent c)233 public void update(Graphics g, JComponent c) { 234 SynthContext context = getContext(c); 235 236 SynthLookAndFeel.update(context, g); 237 context.getPainter().paintMenuBackground(context, 238 g, 0, 0, c.getWidth(), c.getHeight()); 239 paint(context, g); 240 } 241 242 /** 243 * Paints the specified component according to the Look and Feel. 244 * <p>This method is not used by Synth Look and Feel. 245 * Painting is handled by the {@link #paint(SynthContext,Graphics)} method. 246 * 247 * @param g the {@code Graphics} object used for painting 248 * @param c the component being painted 249 * @see #paint(SynthContext,Graphics) 250 */ 251 @Override paint(Graphics g, JComponent c)252 public void paint(Graphics g, JComponent c) { 253 SynthContext context = getContext(c); 254 255 paint(context, g); 256 } 257 258 /** 259 * Paints the specified component. This implementation does nothing. 260 * 261 * @param context context for the component being painted 262 * @param g the {@code Graphics} object used for painting 263 * @see #update(Graphics,JComponent) 264 */ paint(SynthContext context, Graphics g)265 protected void paint(SynthContext context, Graphics g) { 266 SynthContext accContext = getContext(menuItem, 267 Region.MENU_ITEM_ACCELERATOR); 268 // Refetch the appropriate check indicator for the current state 269 String prefix = getPropertyPrefix(); 270 Icon checkIcon = style.getIcon(context, prefix + ".checkIcon"); 271 Icon arrowIcon = style.getIcon(context, prefix + ".arrowIcon"); 272 SynthGraphicsUtils.paint(context, accContext, g, checkIcon, arrowIcon, 273 acceleratorDelimiter, defaultTextIconGap, getPropertyPrefix()); 274 } 275 276 /** 277 * {@inheritDoc} 278 */ 279 @Override paintBorder(SynthContext context, Graphics g, int x, int y, int w, int h)280 public void paintBorder(SynthContext context, Graphics g, int x, 281 int y, int w, int h) { 282 context.getPainter().paintMenuBorder(context, g, x, y, w, h); 283 } 284 285 /** 286 * {@inheritDoc} 287 */ 288 @Override propertyChange(PropertyChangeEvent e)289 public void propertyChange(PropertyChangeEvent e) { 290 if (SynthLookAndFeel.shouldUpdateStyle(e) || 291 (e.getPropertyName().equals("ancestor") && UIManager.getBoolean("Menu.useMenuBarForTopLevelMenus"))) { 292 updateStyle((JMenu)e.getSource()); 293 } 294 } 295 } 296