1 /*
   2  * Copyright (c) 2002, 2010, 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.synth;
  27 
  28 import javax.swing.*;
  29 import javax.swing.plaf.*;
  30 import javax.swing.plaf.basic.*;
  31 import java.awt.Graphics;
  32 import java.beans.PropertyChangeListener;
  33 import java.beans.PropertyChangeEvent;
  34 
  35 /**
  36  * Provides the Synth L&F UI delegate for
  37  * {@link javax.swing.JPopupMenu}.
  38  *
  39  * @author Georges Saab
  40  * @author David Karlton
  41  * @author Arnaud Weber
  42  * @since 1.7
  43  */
  44 public class SynthPopupMenuUI extends BasicPopupMenuUI
  45                               implements PropertyChangeListener, SynthUI {
  46     private SynthStyle style;
  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      */
  54     public static ComponentUI createUI(JComponent x) {
  55         return new SynthPopupMenuUI();
  56     }
  57 
  58     /**
  59      * @inheritDoc
  60      */
  61     @Override
  62     public void installDefaults() {
  63         if (popupMenu.getLayout() == null ||
  64             popupMenu.getLayout() instanceof UIResource) {
  65             popupMenu.setLayout(new SynthMenuLayout(popupMenu, BoxLayout.Y_AXIS));
  66         }
  67         updateStyle(popupMenu);
  68     }
  69 
  70     private void updateStyle(JComponent c) {
  71         SynthContext context = getContext(c, ENABLED);
  72         SynthStyle oldStyle = style;
  73         style = SynthLookAndFeel.updateStyle(context, this);
  74         if (style != oldStyle) {
  75             if (oldStyle != null) {
  76                 uninstallKeyboardActions();
  77                 installKeyboardActions();
  78             }
  79         }
  80         context.dispose();
  81     }
  82 
  83     /**
  84      * @inheritDoc
  85      */
  86     @Override
  87     protected void installListeners() {
  88         super.installListeners();
  89         popupMenu.addPropertyChangeListener(this);
  90     }
  91 
  92     /**
  93      * @inheritDoc
  94      */
  95     @Override
  96     protected void uninstallDefaults() {
  97         SynthContext context = getContext(popupMenu, ENABLED);
  98 
  99         style.uninstallDefaults(context);
 100         context.dispose();
 101         style = null;
 102 
 103         if (popupMenu.getLayout() instanceof UIResource) {
 104             popupMenu.setLayout(null);
 105         }
 106     }
 107 
 108     /**
 109      * @inheritDoc
 110      */
 111     @Override
 112     protected void uninstallListeners() {
 113         super.uninstallListeners();
 114         popupMenu.removePropertyChangeListener(this);
 115     }
 116 
 117     /**
 118      * @inheritDoc
 119      */
 120     @Override
 121     public SynthContext getContext(JComponent c) {
 122         return getContext(c, getComponentState(c));
 123     }
 124 
 125     private SynthContext getContext(JComponent c, int state) {
 126         return SynthContext.getContext(SynthContext.class, c,
 127                     SynthLookAndFeel.getRegion(c), style, state);
 128     }
 129 
 130     private int getComponentState(JComponent c) {
 131         return SynthLookAndFeel.getComponentState(c);
 132     }
 133 
 134     /**
 135      * Notifies this UI delegate to repaint the specified component.
 136      * This method paints the component background, then calls
 137      * the {@link #paint(SynthContext,Graphics)} method.
 138      *
 139      * <p>In general, this method does not need to be overridden by subclasses.
 140      * All Look and Feel rendering code should reside in the {@code paint} method.
 141      *
 142      * @param g the {@code Graphics} object used for painting
 143      * @param c the component being painted
 144      * @see #paint(SynthContext,Graphics)
 145      */
 146     @Override
 147     public void update(Graphics g, JComponent c) {
 148         SynthContext context = getContext(c);
 149 
 150         SynthLookAndFeel.update(context, g);
 151         context.getPainter().paintPopupMenuBackground(context,
 152                           g, 0, 0, c.getWidth(), c.getHeight());
 153         paint(context, g);
 154         context.dispose();
 155     }
 156 
 157     /**
 158      * Paints the specified component according to the Look and Feel.
 159      * <p>This method is not used by Synth Look and Feel.
 160      * Painting is handled by the {@link #paint(SynthContext,Graphics)} method.
 161      *
 162      * @param g the {@code Graphics} object used for painting
 163      * @param c the component being painted
 164      * @see #paint(SynthContext,Graphics)
 165      */
 166     @Override
 167     public void paint(Graphics g, JComponent c) {
 168         SynthContext context = getContext(c);
 169 
 170         paint(context, g);
 171         context.dispose();
 172     }
 173 
 174     /**
 175      * Paints the specified component. This implementation does nothing.
 176      *
 177      * @param context context for the component being painted
 178      * @param g the {@code Graphics} object used for painting
 179      * @see #update(Graphics,JComponent)
 180      */
 181     protected void paint(SynthContext context, Graphics g) {
 182     }
 183 
 184     /**
 185      * @inheritDoc
 186      */
 187     @Override
 188     public void paintBorder(SynthContext context, Graphics g, int x,
 189                             int y, int w, int h) {
 190         context.getPainter().paintPopupMenuBorder(context, g, x, y, w, h);
 191     }
 192 
 193     /**
 194      * @inheritDoc
 195      */
 196     @Override
 197     public void propertyChange(PropertyChangeEvent e) {
 198         if (SynthLookAndFeel.shouldUpdateStyle(e)) {
 199             updateStyle(popupMenu);
 200         }
 201     }
 202 }