       1 /*
       2  * Copyright (c) 1997, 2016, 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 sun.swing.DefaultLookup;
      29 import sun.swing.UIAction;
      30 import java.awt.*;
      31 import java.awt.event.*;
      32 import java.beans.*;
      33 import javax.swing.*;
      34 import javax.swing.event.*;
      35 import javax.swing.plaf.ActionMapUIResource;
      36 import javax.swing.plaf.ButtonUI;
      37 import javax.swing.plaf.ComponentInputMapUIResource;
      38
      39 /**
      40  * Button Listener
      41  *
      42  * @author Jeff Dinkins
      43  * @author Arnaud Weber (keyboard UI support)
      44  */
      45
      46 public class BasicButtonListener implements MouseListener, MouseMotionListener,
      47                                    FocusListener, ChangeListener, PropertyChangeListener
      48 {
      49     private long lastPressedTimestamp = -1;
      50     private boolean shouldDiscardRelease = false;
      51
      52     /**
      53      * Populates Buttons actions.
      54      */
      55     static void loadActionMap(LazyActionMap map) {
      56         map.put(new Actions(Actions.PRESS));
      57         map.put(new Actions(Actions.RELEASE));
      58     }
      59
      60
      61     /**
      62      * Constructs a new instance of {@code BasicButtonListener}.
      63      *
      64      * @param b an abstract button
      65      */
      66     public BasicButtonListener(AbstractButton b) {
      67     }
      68
      69     public void propertyChange(PropertyChangeEvent e) {
      70         String prop = e.getPropertyName();
      71         if(prop == AbstractButton.MNEMONIC_CHANGED_PROPERTY) {
      72             updateMnemonicBinding((AbstractButton)e.getSource());
      73         }
      74         else if(prop == AbstractButton.CONTENT_AREA_FILLED_CHANGED_PROPERTY) {
      75             checkOpacity((AbstractButton) e.getSource() );
      76         }
      77         else if(prop == AbstractButton.TEXT_CHANGED_PROPERTY ||
      78                 "font" == prop || "foreground" == prop ||
      79                 "ancestor" == prop || "graphicsConfiguration" == prop) {
      80             AbstractButton b = (AbstractButton) e.getSource();
      81             BasicHTML.updateRenderer(b, b.getText());
      82         }
      83     }
      84
      85     /**
      86      * Checks the opacity of the {@code AbstractButton}.
      87      *
      88      * @param b an abstract button
      89      */
      90     protected void checkOpacity(AbstractButton b) {
      91         b.setOpaque( b.isContentAreaFilled() );
      92     }
      93
      94     /**
      95      * Register default key actions: pressing space to "click" a
      96      * button and registering the keyboard mnemonic (if any).
      97      *
      98      * @param c a component
      99      */
     100     public void installKeyboardActions(JComponent c) {
     101         AbstractButton b = (AbstractButton)c;
     102         // Update the mnemonic binding.
     103         updateMnemonicBinding(b);
     104
     105         LazyActionMap.installLazyActionMap(c, BasicButtonListener.class,
     106                                            "Button.actionMap");
     107
     108         InputMap km = getInputMap(JComponent.WHEN_FOCUSED, c);
     109
     110         SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, km);
     111     }
     112
     113     /**
     114      * Unregister default key actions.
     115      *
     116      * @param c a component
     117      */
     118     public void uninstallKeyboardActions(JComponent c) {
     119         SwingUtilities.replaceUIInputMap(c, JComponent.
     120                                          WHEN_IN_FOCUSED_WINDOW, null);
     121         SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, null);
     122         SwingUtilities.replaceUIActionMap(c, null);
     123     }
     124
     125     /**
     126      * Returns the InputMap for condition <code>condition</code>. Called as
     127      * part of <code>installKeyboardActions</code>.
     128      */
     129     InputMap getInputMap(int condition, JComponent c) {
     130         if (condition == JComponent.WHEN_FOCUSED) {
     131             BasicButtonUI ui = (BasicButtonUI)BasicLookAndFeel.getUIOfType(
     132                          ((AbstractButton)c).getUI(), BasicButtonUI.class);
     133             if (ui != null) {
     134                 return (InputMap)DefaultLookup.get(
     135                              c, ui, ui.getPropertyPrefix() + "focusInputMap");
     136             }
     137         }
     138         return null;
     139     }
     140
     141     /**
     142      * Resets the binding for the mnemonic in the WHEN_IN_FOCUSED_WINDOW
     143      * UI InputMap.
     144      */
     145     void updateMnemonicBinding(AbstractButton b) {
     146         int m = b.getMnemonic();
     147         if(m != 0) {
     148             InputMap map = SwingUtilities.getUIInputMap(
     149                                 b, JComponent.WHEN_IN_FOCUSED_WINDOW);
     150
     151             if (map == null) {
     152                 map = new ComponentInputMapUIResource(b);
     153                 SwingUtilities.replaceUIInputMap(b,
     154                                JComponent.WHEN_IN_FOCUSED_WINDOW, map);
     155             }
     156             map.clear();
     157             map.put(KeyStroke.getKeyStroke(m, BasicLookAndFeel.getFocusAcceleratorKeyMask(), false),
     158                     "pressed");

     159             map.put(KeyStroke.getKeyStroke(m, BasicLookAndFeel.getFocusAcceleratorKeyMask(), true),

     160                     "released");
     161             map.put(KeyStroke.getKeyStroke(m, 0, true), "released");
     162         }
     163         else {
     164             InputMap map = SwingUtilities.getUIInputMap(b, JComponent.
     165                                              WHEN_IN_FOCUSED_WINDOW);
     166             if (map != null) {
     167                 map.clear();
     168             }
     169         }
     170     }
     171
     172     public void stateChanged(ChangeEvent e) {
     173         AbstractButton b = (AbstractButton) e.getSource();
     174         b.repaint();
     175     }
     176
     177     public void focusGained(FocusEvent e) {
     178         AbstractButton b = (AbstractButton) e.getSource();
     179         if (b instanceof JButton && ((JButton)b).isDefaultCapable()) {
     180             JRootPane root = b.getRootPane();
     181             if (root != null) {
     182                BasicButtonUI ui = (BasicButtonUI)BasicLookAndFeel.getUIOfType(
     183                          b.getUI(), BasicButtonUI.class);
     184                if (ui != null && DefaultLookup.getBoolean(b, ui,
     185                                    ui.getPropertyPrefix() +
     186                                    "defaultButtonFollowsFocus", true)) {
     187                    root.putClientProperty("temporaryDefaultButton", b);
     188                    root.setDefaultButton((JButton)b);
     189                    root.putClientProperty("temporaryDefaultButton", null);
     190                }
     191             }
     192         }
     193         b.repaint();
     194     }
     195
     196     public void focusLost(FocusEvent e) {
     197         AbstractButton b = (AbstractButton) e.getSource();
     198         JRootPane root = b.getRootPane();
     199         if (root != null) {
     200            JButton initialDefault = (JButton)root.getClientProperty("initialDefaultButton");
     201            if (b != initialDefault) {
     202                BasicButtonUI ui = (BasicButtonUI)BasicLookAndFeel.getUIOfType(
     203                          b.getUI(), BasicButtonUI.class);
     204                if (ui != null && DefaultLookup.getBoolean(b, ui,
     205                                    ui.getPropertyPrefix() +
     206                                    "defaultButtonFollowsFocus", true)) {
     207                    root.setDefaultButton(initialDefault);
     208                }
     209            }
     210         }
     211
     212         ButtonModel model = b.getModel();
     213         model.setPressed(false);
     214         model.setArmed(false);
     215         b.repaint();
     216     }
     217
     218     public void mouseMoved(MouseEvent e) {
     219     }
     220
     221
     222     public void mouseDragged(MouseEvent e) {
     223     }
     224
     225     public void mouseClicked(MouseEvent e) {
     226     }
     227
     228     public void mousePressed(MouseEvent e) {
     229        if (SwingUtilities.isLeftMouseButton(e) ) {
     230           AbstractButton b = (AbstractButton) e.getSource();
     231
     232           if(b.contains(e.getX(), e.getY())) {
     233               long lastTime = lastPressedTimestamp;
     234               lastPressedTimestamp = e.getWhen();
     235               long timeSinceLastClick = lastPressedTimestamp - lastTime;
     236               if (lastTime != -1 &&
     237                   timeSinceLastClick > 0 &&
     238                   timeSinceLastClick < b.getMultiClickThreshhold()) {
     239
     240                   shouldDiscardRelease = true;
     241                   return;
     242               }
     243
     244              ButtonModel model = b.getModel();
     245              if (!model.isEnabled()) {
     246                 // Disabled buttons ignore all input...
     247                 return;
     248              }
     249              if (!model.isArmed()) {
     250                 // button not armed, should be
     251                 model.setArmed(true);
     252              }
     253              model.setPressed(true);
     254              if(!b.hasFocus() && b.isRequestFocusEnabled()) {
     255                 b.requestFocus();
     256              }
     257           }
     258        }
     259     }
     260
     261     public void mouseReleased(MouseEvent e) {
     262         if (SwingUtilities.isLeftMouseButton(e)) {
     263             // Support for multiClickThreshhold
     264             if (shouldDiscardRelease) {
     265                 shouldDiscardRelease = false;
     266                 return;
     267             }
     268             AbstractButton b = (AbstractButton) e.getSource();
     269             ButtonModel model = b.getModel();
     270             model.setPressed(false);
     271             model.setArmed(false);
     272         }
     273     }
     274
     275     public void mouseEntered(MouseEvent e) {
     276         AbstractButton b = (AbstractButton) e.getSource();
     277         ButtonModel model = b.getModel();
     278         if (b.isRolloverEnabled() && !SwingUtilities.isLeftMouseButton(e)) {
     279             model.setRollover(true);
     280         }
     281         if (model.isPressed())
     282                 model.setArmed(true);
     283     }
     284
     285     public void mouseExited(MouseEvent e) {
     286         AbstractButton b = (AbstractButton) e.getSource();
     287         ButtonModel model = b.getModel();
     288         if(b.isRolloverEnabled()) {
     289             model.setRollover(false);
     290         }
     291         model.setArmed(false);
     292     }
     293
     294
     295     /**
     296      * Actions for Buttons. Two types of action are supported:
     297      * pressed: Moves the button to a pressed state
     298      * released: Disarms the button.
     299      */
     300     private static class Actions extends UIAction {
     301         private static final String PRESS = "pressed";
     302         private static final String RELEASE = "released";
     303
     304         Actions(String name) {
     305             super(name);
     306         }
     307
     308         public void actionPerformed(ActionEvent e) {
     309             AbstractButton b = (AbstractButton)e.getSource();
     310             String key = getName();
     311             if (key == PRESS) {
     312                 ButtonModel model = b.getModel();
     313                 model.setArmed(true);
     314                 model.setPressed(true);
     315                 if(!b.hasFocus()) {
     316                     b.requestFocus();
     317                 }
     318             }
     319             else if (key == RELEASE) {
     320                 ButtonModel model = b.getModel();
     321                 model.setPressed(false);
     322                 model.setArmed(false);
     323             }
     324         }
     325
     326         @Override
     327         public boolean accept(Object sender) {
     328             return !((sender instanceof AbstractButton) &&
     329                     !((AbstractButton)sender).getModel().isEnabled());
     330         }
     331     }
     332 }
    --- EOF ---