1 /*
   2  * Copyright (c) 2011, 2012, 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.apple.laf;
  27 
  28 import java.awt.*;
  29 import java.beans.*;
  30 
  31 import javax.swing.*;
  32 import javax.swing.plaf.*;
  33 import javax.swing.plaf.basic.BasicMenuItemUI;
  34 
  35 import apple.laf.JRSUIConstants.Size;
  36 
  37 // TODO: no screen menu bar for now
  38 public class AquaMenuItemUI extends BasicMenuItemUI implements AquaMenuPainter.Client/*, ScreenMenuItemUI*/ {
  39     static final int kPlain = 0, kCheckBox = 1, kRadioButton = 2;
  40     static final String sPropertyPrefixes[] = { "MenuItem", "CheckBoxMenuItem", "RadioButtonMenuItem" };
  41 
  42     boolean fIsScreenMenuItem = false;
  43     boolean fIsIndeterminate = false;
  44     int fType;
  45 
  46     AquaMenuItemUI(final int type) {
  47         super();
  48         fType = type;
  49     }
  50 
  51     public static ComponentUI createUI(final JComponent c) {
  52         int type = kPlain;
  53         if (c instanceof JCheckBoxMenuItem) type = kCheckBox;
  54         if (c instanceof JRadioButtonMenuItem) type = kRadioButton;
  55         return new AquaMenuItemUI(type);
  56     }
  57 
  58     // The only real difference between the three is which property prefix it returns
  59     // and therefore which icons!
  60     protected String getPropertyPrefix() {
  61         return sPropertyPrefixes[fType];
  62     }
  63 
  64     @Override
  65     protected void installListeners() {
  66         super.installListeners();
  67         IndeterminateListener.install(menuItem);
  68     }
  69 
  70     @Override
  71     protected void uninstallListeners() {
  72         IndeterminateListener.uninstall(menuItem);
  73         super.uninstallListeners();
  74     }
  75 
  76     public void updateListenersForScreenMenuItem() {
  77         setIsScreenMenu(true);
  78     }
  79 
  80     // Users can dynamically change the kind of menu we're on by calling JPopupMenu.setInvoker
  81     // so we need to be prepared to put the listeners back on
  82     protected void setIsScreenMenu(final boolean isScreenMenuItem) {
  83         if (fIsScreenMenuItem != isScreenMenuItem) {
  84             fIsScreenMenuItem = isScreenMenuItem;
  85             if (fIsScreenMenuItem) removeListeners();
  86             else addListeners();
  87         }
  88     }
  89 
  90     protected void removeListeners() {
  91         menuItem.removeMouseListener(mouseInputListener);
  92         menuItem.removeMouseMotionListener(mouseInputListener);
  93         menuItem.removeMenuDragMouseListener(menuDragMouseListener);
  94     }
  95 
  96     protected void addListeners() {
  97         menuItem.addMouseListener(mouseInputListener);
  98         menuItem.addMouseMotionListener(mouseInputListener);
  99         menuItem.addMenuDragMouseListener(menuDragMouseListener);
 100     }
 101 
 102     protected void paintMenuItem(final Graphics g, final JComponent c, final Icon localCheckIcon, final Icon localArrowIcon, final Color background, final Color foreground, final int localDefaultTextIconGap) {
 103         AquaMenuPainter.instance().paintMenuItem(this, g, c, localCheckIcon, localArrowIcon, background, foreground, disabledForeground, selectionForeground, localDefaultTextIconGap, acceleratorFont);
 104     }
 105 
 106     protected Dimension getPreferredMenuItemSize(final JComponent c, final Icon localCheckIcon, final Icon localArrowIcon, final int localDefaultTextIconGap) {
 107         return AquaMenuPainter.instance().getPreferredMenuItemSize(c, localCheckIcon, localArrowIcon, localDefaultTextIconGap, acceleratorFont);
 108     }
 109 
 110     public void update(final Graphics g, final JComponent c) {
 111         if (c.isOpaque()) {
 112             // sja fix ((PenGraphics)g).alphaClearRect(0,0,c.getWidth(),c.getHeight());
 113             final Color oldColor = g.getColor();
 114             g.setColor(c.getBackground());
 115             g.fillRect(0, 0, c.getWidth(), c.getHeight());
 116             g.setColor(oldColor);
 117         }
 118 
 119         paint(g, c);
 120     }
 121 
 122     public void paintBackground(final Graphics g, final JComponent c, final int menuWidth, final int menuHeight) {
 123         if ((c.getParent() instanceof JMenuBar)) return;
 124         final Color oldColor = g.getColor();
 125 
 126         g.setColor(c.getBackground());
 127         g.fillRect(0, 0, menuWidth, menuHeight);
 128         if (((JMenuItem)c).isBorderPainted()) {
 129             if (((JMenuItem)c).getModel().isArmed()) {
 130                 AquaMenuPainter.instance().paintSelectedMenuItemBackground(g, menuWidth, menuHeight);
 131             }
 132             //getTheme().drawMenuItem(c, g, 0, 0, menuWidth, menuHeight);
 133         } else {
 134             // If selected, use black (see AquaLookAndFeel "Menu.selectionBackground")
 135             if (((JMenuItem)c).getModel().isArmed()) {
 136                 final Color holdc = g.getColor();
 137                 g.setColor(Color.black);
 138                 g.fillRect(0, 0, menuWidth, menuHeight);
 139                 g.setColor(holdc);
 140             } else {
 141                 g.setColor(Color.green);
 142                 g.fillRect(0, 0, menuWidth, menuHeight);
 143                 //super.paintBackground(g,c,menuWidth, menuHeight); //getTheme().drawMenuBackground((Component)c, g, (short)1, 0, 0, menuWidth, menuHeight);
 144             }
 145         }
 146         g.setColor(oldColor);
 147     }
 148 
 149     protected void doClick(final MenuSelectionManager msm) {
 150         final Dimension size = menuItem.getSize();
 151         AquaUtils.blinkMenu(new AquaUtils.Selectable() {
 152             public void paintSelected(final boolean selected) {
 153                 menuItem.setArmed(selected);
 154                 menuItem.paintImmediately(0, 0, size.width, size.height);
 155             }
 156         });
 157         super.doClick(msm);
 158     }
 159 
 160     static final IndeterminateListener INDETERMINATE_LISTENER = new IndeterminateListener();
 161     static class IndeterminateListener implements PropertyChangeListener {
 162         static final String CLIENT_PROPERTY_KEY = "JMenuItem.selectedState";
 163 
 164         static void install(final JMenuItem menuItem) {
 165             menuItem.addPropertyChangeListener(CLIENT_PROPERTY_KEY, INDETERMINATE_LISTENER);
 166             apply(menuItem, menuItem.getClientProperty(CLIENT_PROPERTY_KEY));
 167         }
 168 
 169         static void uninstall(final JMenuItem menuItem) {
 170             menuItem.removePropertyChangeListener(CLIENT_PROPERTY_KEY, INDETERMINATE_LISTENER);
 171         }
 172 
 173         public void propertyChange(final PropertyChangeEvent evt) {
 174             final String key = evt.getPropertyName();
 175             if (!CLIENT_PROPERTY_KEY.equalsIgnoreCase(key)) return;
 176 
 177             final Object source = evt.getSource();
 178             if (!(source instanceof JMenuItem)) return;
 179 
 180             final JMenuItem c = (JMenuItem)source;
 181             apply(c, evt.getNewValue());
 182         }
 183 
 184         static void apply(final JMenuItem menuItem, final Object value) {
 185             final ButtonUI ui = menuItem.getUI();
 186             if (!(ui instanceof AquaMenuItemUI)) return;
 187 
 188             final AquaMenuItemUI aquaUI = (AquaMenuItemUI)ui;
 189 
 190             if (aquaUI.fIsIndeterminate = "indeterminate".equals(value)) {
 191                 aquaUI.checkIcon = UIManager.getIcon(aquaUI.getPropertyPrefix() + ".dashIcon");
 192             } else {
 193                 aquaUI.checkIcon = UIManager.getIcon(aquaUI.getPropertyPrefix() + ".checkIcon");
 194             }
 195         }
 196 
 197         public static boolean isIndeterminate(final JMenuItem menuItem) {
 198             return "indeterminate".equals(menuItem.getClientProperty(CLIENT_PROPERTY_KEY));
 199         }
 200     }
 201 }