1 /*
   2  * Copyright (c) 1999, 2014, 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.basic;
  27 
  28 import java.awt.event.ActionEvent;
  29 import java.awt.KeyboardFocusManager;
  30 import java.awt.Component;
  31 import java.awt.Point;
  32 import java.awt.Rectangle;
  33 import java.beans.PropertyChangeEvent;
  34 import java.beans.PropertyChangeListener;
  35 import javax.swing.*;
  36 import javax.swing.plaf.*;
  37 import sun.swing.DefaultLookup;
  38 import sun.swing.UIAction;
  39 
  40 /**
  41  * Basic implementation of RootPaneUI, there is one shared between all
  42  * JRootPane instances.
  43  *
  44  * @author Scott Violet
  45  * @since 1.3
  46  */
  47 public class BasicRootPaneUI extends RootPaneUI implements
  48                   PropertyChangeListener {
  49     private static RootPaneUI rootPaneUI = new BasicRootPaneUI();
  50 
  51     /**
  52      * Returns a new instance of {@code BasicRootPaneUI}.
  53      *
  54      * @param c a component
  55      * @return a new instance of {@code BasicRootPaneUI}
  56      */
  57     public static ComponentUI createUI(JComponent c) {
  58         return rootPaneUI;
  59     }
  60 
  61     public void installUI(JComponent c) {
  62         installDefaults((JRootPane)c);
  63         installComponents((JRootPane)c);
  64         installListeners((JRootPane)c);
  65         installKeyboardActions((JRootPane)c);
  66     }
  67 
  68 
  69     public void uninstallUI(JComponent c) {
  70         uninstallDefaults((JRootPane)c);
  71         uninstallComponents((JRootPane)c);
  72         uninstallListeners((JRootPane)c);
  73         uninstallKeyboardActions((JRootPane)c);
  74     }
  75 
  76     /**
  77      * Installs default properties.
  78      *
  79      * @param c an instance of {@code JRootPane}
  80      */
  81     protected void installDefaults(JRootPane c){
  82         LookAndFeel.installProperty(c, "opaque", Boolean.FALSE);
  83     }
  84 
  85     /**
  86      * Installs components.
  87      *
  88      * @param root an instance of {@code JRootPane}
  89      */
  90     protected void installComponents(JRootPane root) {
  91     }
  92 
  93     /**
  94      * Registers listeners.
  95      *
  96      * @param root an instance of {@code JRootPane}
  97      */
  98     protected void installListeners(JRootPane root) {
  99         root.addPropertyChangeListener(this);
 100     }
 101 
 102     /**
 103      * Registers keyboard actions.
 104      *
 105      * @param root an instance of {@code JRootPane}
 106      */
 107     protected void installKeyboardActions(JRootPane root) {
 108         InputMap km = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, root);
 109         SwingUtilities.replaceUIInputMap(root,
 110                 JComponent.WHEN_IN_FOCUSED_WINDOW, km);
 111         km = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
 112                 root);
 113         SwingUtilities.replaceUIInputMap(root,
 114                 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, km);
 115 
 116         LazyActionMap.installLazyActionMap(root, BasicRootPaneUI.class,
 117                 "RootPane.actionMap");
 118         updateDefaultButtonBindings(root);
 119     }
 120 
 121     /**
 122      * Uninstalls default properties.
 123      *
 124      * @param root an instance of {@code JRootPane}
 125      */
 126     protected void uninstallDefaults(JRootPane root) {
 127     }
 128 
 129     /**
 130      * Unregisters components.
 131      *
 132      * @param root an instance of {@code JRootPane}
 133      */
 134     protected void uninstallComponents(JRootPane root) {
 135     }
 136 
 137     /**
 138      * Unregisters listeners.
 139      *
 140      * @param root an instance of {@code JRootPane}
 141      */
 142     protected void uninstallListeners(JRootPane root) {
 143         root.removePropertyChangeListener(this);
 144     }
 145 
 146     /**
 147      * Unregisters keyboard actions.
 148      *
 149      * @param root an instance of {@code JRootPane}
 150      */
 151     protected void uninstallKeyboardActions(JRootPane root) {
 152         SwingUtilities.replaceUIInputMap(root, JComponent.
 153                 WHEN_IN_FOCUSED_WINDOW, null);
 154         SwingUtilities.replaceUIActionMap(root, null);
 155     }
 156 
 157     InputMap getInputMap(int condition, JComponent c) {
 158         if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
 159             return (InputMap)DefaultLookup.get(c, this,
 160                                        "RootPane.ancestorInputMap");
 161         }
 162 
 163         if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
 164             return createInputMap(condition, c);
 165         }
 166         return null;
 167     }
 168 
 169     ComponentInputMap createInputMap(int condition, JComponent c) {
 170         return new RootPaneInputMap(c);
 171     }
 172 
 173     static void loadActionMap(LazyActionMap map) {
 174         map.put(new Actions(Actions.PRESS));
 175         map.put(new Actions(Actions.RELEASE));
 176         map.put(new Actions(Actions.POST_POPUP));
 177     }
 178 
 179     /**
 180      * Invoked when the default button property has changed. This reloads
 181      * the bindings from the defaults table with name
 182      * <code>RootPane.defaultButtonWindowKeyBindings</code>.
 183      */
 184     void updateDefaultButtonBindings(JRootPane root) {
 185         InputMap km = SwingUtilities.getUIInputMap(root, JComponent.
 186                                                WHEN_IN_FOCUSED_WINDOW);
 187         while (km != null && !(km instanceof RootPaneInputMap)) {
 188             km = km.getParent();
 189         }
 190         if (km != null) {
 191             km.clear();
 192             if (root.getDefaultButton() != null) {
 193                 Object[] bindings = (Object[])DefaultLookup.get(root, this,
 194                            "RootPane.defaultButtonWindowKeyBindings");
 195                 if (bindings != null) {
 196                     LookAndFeel.loadKeyBindings(km, bindings);
 197                 }
 198             }
 199         }
 200     }
 201 
 202     /**
 203      * Invoked when a property changes on the root pane. If the event
 204      * indicates the <code>defaultButton</code> has changed, this will
 205      * reinstall the keyboard actions.
 206      */
 207     public void propertyChange(PropertyChangeEvent e) {
 208         if(e.getPropertyName().equals("defaultButton")) {
 209             JRootPane rootpane = (JRootPane)e.getSource();
 210             updateDefaultButtonBindings(rootpane);
 211             if (rootpane.getClientProperty("temporaryDefaultButton") == null) {
 212                 rootpane.putClientProperty("initialDefaultButton", e.getNewValue());
 213             }
 214         }
 215     }
 216 
 217 
 218     static class Actions extends UIAction {
 219         public static final String PRESS = "press";
 220         public static final String RELEASE = "release";
 221         public static final String POST_POPUP = "postPopup";
 222 
 223         Actions(String name) {
 224             super(name);
 225         }
 226 
 227         public void actionPerformed(ActionEvent evt) {
 228             JRootPane root = (JRootPane)evt.getSource();
 229             JButton owner = root.getDefaultButton();
 230             String key = getName();
 231 
 232             if (key == POST_POPUP) { // Action to post popup
 233                 Component c = KeyboardFocusManager
 234                         .getCurrentKeyboardFocusManager()
 235                          .getFocusOwner();
 236 
 237                 if(c instanceof JComponent) {
 238                     JComponent src = (JComponent) c;
 239                     JPopupMenu jpm = src.getComponentPopupMenu();
 240                     if(jpm != null) {
 241                         Point pt = src.getPopupLocation(null);
 242                         if(pt == null) {
 243                             Rectangle vis = src.getVisibleRect();
 244                             pt = new Point(vis.x+vis.width/2,
 245                                            vis.y+vis.height/2);
 246                         }
 247                         jpm.show(c, pt.x, pt.y);
 248                     }
 249                 }
 250             }
 251             else if (owner != null
 252                      && SwingUtilities.getRootPane(owner) == root) {
 253                 if (key == PRESS) {
 254                     owner.doClick(20);
 255                 }
 256             }
 257         }
 258 
 259         public boolean isEnabled(Object sender) {
 260             String key = getName();
 261             if(key == POST_POPUP) {
 262                 MenuElement[] elems = MenuSelectionManager
 263                         .defaultManager()
 264                         .getSelectedPath();
 265                 if(elems != null && elems.length != 0) {
 266                     return false;
 267                     // We shall not interfere with already opened menu
 268                 }
 269 
 270                 Component c = KeyboardFocusManager
 271                        .getCurrentKeyboardFocusManager()
 272                         .getFocusOwner();
 273                 if(c instanceof JComponent) {
 274                     JComponent src = (JComponent) c;
 275                     return src.getComponentPopupMenu() != null;
 276                 }
 277 
 278                 return false;
 279             }
 280 
 281             if (sender != null && sender instanceof JRootPane) {
 282                 JButton owner = ((JRootPane)sender).getDefaultButton();
 283                 return (owner != null && owner.getModel().isEnabled());
 284             }
 285             return true;
 286         }
 287     }
 288 
 289     @SuppressWarnings("serial") // JDK-implementation class
 290     private static class RootPaneInputMap extends ComponentInputMapUIResource {
 291         public RootPaneInputMap(JComponent c) {
 292             super(c);
 293         }
 294     }
 295 }
--- EOF ---